Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert an Optional to an OptionalInt?

I have an Optional that I want to "convert" to an OptionalInt, but there doesn't seem to be a simple way to do this.

Here's what I want to do (contrived example):

public OptionalInt getInt() {
    return Optional.ofNullable(someString).filter(s -> s.matches("\\d+")).mapToInt(Integer::parseInt);
}

However, there's no mapToInt() method for Optional.

The best I could come up with is:

return Optional.ofNullable(someString)
    .filter(s -> s.matches("\\d+"))
    .map(s -> OptionalInt.of(Integer.parseInt(s)))
    .orElse(OptionalInt.empty());

but that seems inelegant.

Am I missing something from the JDK that can make the conversion more elegant?

like image 602
Bohemian Avatar asked Jan 11 '16 03:01

Bohemian


People also ask

What is the difference between optionalint and optional in Java?

OptionalInt is a container class that contains null or not null int values. OptionalInt is a primitive int version of Optional class whereas Optional is an Optional class for Integer Object. It is defined java.util package and aviable since java8 version.

What is the use of return in optionalint?

Returns an empty OptionalInt instance. Indicates whether some other object is "equal to" this OptionalInt. If a value is present in this OptionalInt, returns the value, otherwise throws NoSuchElementException. Returns the hash code value of the present value, if any, or 0 (zero) if no value is present.

What is the use of == () method in optionalint?

This is a value-based class; use of identity-sensitive operations (including reference equality ( == ), identity hash code, or synchronization) on instances of OptionalInt may have unpredictable results and should be avoided. Returns an empty OptionalInt instance. Indicates whether some other object is "equal to" this OptionalInt.

What is the use of optional in C++?

std::optional is a wrapper type to express “null-able” types. use operator *, operator->, value () or value_or () to access the underlying value. std::optional is implicitly converted to bool so that you can easily check if it contains a value or not.


3 Answers

While the code isn't more readable than an ordinary conditional expression, there is a simple solution:

public OptionalInt getInt() {
    return Stream.of(someString).filter(s -> s != null && s.matches("\\d+"))
        .mapToInt(Integer::parseInt).findAny();
}

With Java 9, you could use

public OptionalInt getInt() {
    return Stream.ofNullable(someString).filter(s -> s.matches("\\d+"))
        .mapToInt(Integer::parseInt).findAny();
}

As said, neither is more readable than an ordinary conditional expression, but I think, it still looks better than using mapOrElseGet (and the first variant doesn't need Java 9.

like image 54
Holger Avatar answered Oct 06 '22 11:10

Holger


If you have any object and not just a String, you can temporarily go through a Stream:

public static <T> OptionalInt toOptionalInt(Optional<T> optional, ToIntFunction<? super T> func) {
  return optional.map(Stream::of).orElseGet(Stream::empty)
    .mapToInt(func)
    .findFirst();
}

This solution has the advantage to be a one-liner, meaning you can copy/paste the content of the method and just change func to whatever you want. The disadvantage is going through a Stream to achieve what you want. But if you want a generic one-liner, this is it.

If you want a utility method, you probably prefer to use the following:

public static <T> OptionalInt toOptionalInt(Optional<T> optional, ToIntFunction<? super T> func) {
  if (optional.isPresent()) {
    return OptionalInt.of(func.applyAsInt(optional.get()));
  } else {
    return OptionalInt.empty();
  }
}
like image 27
Olivier Grégoire Avatar answered Oct 06 '22 09:10

Olivier Grégoire


No, there's no way to do it in more elegant way using standard Java API. And as far as I know it's not planned to add such methods in JDK-9. I asked Paul Sandoz about adding mapToInt, etc., here's his answer:

Me:

Isn't it a good idea to provide also a way to transfer between Optional types like mapToInt, mapToObj, etc., like it's done in Stream API?

Paul:

I don’t wanna go there, my response is transform Optional* into a *Stream. An argument for adding mapOrElseGet (notice that the primitive variants return U) is that other functionality can be composed from it.

So you will likely to have in Java-9:

return Optional.of(someString).filter(s -> s.matches("\\d+"))
     .mapOrElseGet(s -> OptionalInt.of(Integer.parseInt(s)), OptionalInt::empty);

But nothing more.

That's because JDK authors insist that the Optional class and its primitive friends (especially primitive friends) should not be widely used, it's just a convenient way to perform a limited set of operations on the return value of methods which may return "the absence of the value". Also primitive optionals are designed for performance improvement, but actually it's much less significant than with streams, so using Optional<Integer> is also fine. With Valhalla project (hopefully to arrive in Java-10) you will be able to use Optional<int> and OptionalInt will become unnecessary.

In your particular case the better way to do it is using ternary operator:

return someString != null && someString.matches("\\d+") ? 
       OptionalInt.of(Integer.parseInt(someString)) : OptionalInt.empty();

I assume that you want to return the OptionalInt from the method. Otherwise it's even more questionable why you would need it.

like image 3
Tagir Valeev Avatar answered Oct 06 '22 11:10

Tagir Valeev