Cast from Optional<> to ArrayList<>
Solution 1
I am presuming your intended semantic is 'if the value is present return a list with a single item, otherwise return an empty list.' In that case I would suggest something like the following:
ArrayList<A> result = new ArrayList<>();
b.c.test().ifPresent(result::add);
return result;
However I would suggest your return type should be List<A>
rather than ArrayList<A>
as that gives you the opportunity to change the type of list without changing the callers. It would also allow you to return Collections.EMPTY_LIST
if the optional value is not present which is more efficient than creating an unnecessary ArrayList
.
Update: there's now an easier option with Java 9:
b.c.test().stream().collect(Collectors.toList());
Update: and even easier option with Java 16:
b.c.test().stream().toList();
Solution 2
In this case, it is possible to not use streams at all:
public static <T> List<T> toList(Optional<T> opt) {
return opt.isPresent()
? Collections.singletonList(opt.get())
: Collections.emptyList();
}
Or, the same code using the functional API:
public static <T> List<T> toList(Optional<T> opt) {
return opt
.map(Collections::singletonList)
.orElseGet(Collections::emptyList);
}
I prefer the upper variant because I know for sure that it doesn't create any unnecessary objects on the Java heap.
Solution 3
If everyone insists on using streams for this issue, it should be more idiomatic than using ifPresent()
Unfortunately, Java 8 does not have a Optional.stream()
method, so it is not possible to do:
optional.stream().collect(Collectors.toList());
see also: Using Java 8's Optional with Stream::flatMap
But in JDK 9, it will be added (and that code actually already runs on Java 9)
Optional<Integer> o = Optional.empty();
final List<Integer> list = o.stream().collect(Collectors.toList());
System.out.println(list);
Solution 4
With Java9, you can do this using the newly added Optional::stream API
:
Optional<List<A>> list;
List<A> collect = list.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
Solution 5
return b.c.test()
.map(Arrays::asList).map(ArrayList::new)
.orElseGet(ArrayList::new);
If the optional has a value, it "maps" it to a List<A>
with Arrays.asList
and then to an ArrayList
via the new ArrayList<A>(List<A>)
constructor; otherwise it yields an empty ArrayList
via the empty constructor.
This could be more explicitly written out as:
return b.c.test()
.map(value -> new ArrayList<A>(Arrays.asList(value)))
.orElseGet(() -> new ArrayList<A>());
user3097712
Updated on August 05, 2022Comments
-
user3097712 almost 2 years
I have the following situation:
public ArrayList<A> getMethods(){ return b.c.test(); }
So, my problem is that
b.c.test()
returns a value withOptional<A>
as return type. But I need to return anArrayList<A>
.So, I tried to cast it and rewrite it to :
public ArrayList<A> getMethods(){ return (ArrayList<A>)b.c.test(); }
But Eclipse says that such a cast from
Optional<A>
toArrayList<A>
is not possible.How can I solve this problem?
-
Ar5hv1r almost 9 years
Optional.empty()
is a static method that returns a new, emptyOptional
. You wantOptional.isPresent()
. There are also cleaner ways to do this (@sprinter's answer). -
Mick Mnemonic almost 9 yearsThis seems excessively verbose; isn't this actually misusing Java 8's functional idioms for a very simple task?
-
sprinter almost 9 years@JoseAntonioDuraOlmos I think you mean
if (opt.isPresent())
rather thanif (!opt.isPresent())
. At the moment this will throw an exception when you try toget
and empty optional. -
Anonymous Coward almost 9 yearsOf course, that is what happens for changing blindly !opt.empty() for !opt.isPresent().
-
John Kugelman almost 9 yearsI dunno, I like this style. I like the lack of temporary variables. I see the complexity as a consequence of the overly specific return type. If it were
List
instead ofArrayList
this could be written more straightforwardly:map(Collections::singletonList).orElseGet(Collections::emptyList)
. I like the way that looks. -
Mick Mnemonic almost 9 yearsIMO, the temporary variable in @sprinter's answer makes the code more readable (and much more concise).
map
andorElseGet
are useful -- when used in the right place. Your solution just reminded me of the caveats presented in Guava's Functionals Explained -- imperative code should be the default, even in Java 8.