Cast from Optional<> to ArrayList<>

53,492

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>());
Share:
53,492
user3097712
Author by

user3097712

Updated on August 05, 2022

Comments

  • user3097712
    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 with Optional<A> as return type. But I need to return an ArrayList<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> to ArrayList<A> is not possible.

    How can I solve this problem?

  • Ar5hv1r
    Ar5hv1r almost 9 years
    Optional.empty() is a static method that returns a new, empty Optional. You want Optional.isPresent(). There are also cleaner ways to do this (@sprinter's answer).
  • Mick Mnemonic
    Mick Mnemonic almost 9 years
    This seems excessively verbose; isn't this actually misusing Java 8's functional idioms for a very simple task?
  • sprinter
    sprinter almost 9 years
    @JoseAntonioDuraOlmos I think you mean if (opt.isPresent()) rather than if (!opt.isPresent()). At the moment this will throw an exception when you try to get and empty optional.
  • Anonymous Coward
    Anonymous Coward almost 9 years
    Of course, that is what happens for changing blindly !opt.empty() for !opt.isPresent().
  • John Kugelman
    John Kugelman almost 9 years
    I 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 of ArrayList this could be written more straightforwardly: map(Collections::singletonList).orElseGet(Collections::empty‌​List). I like the way that looks.
  • Mick Mnemonic
    Mick Mnemonic almost 9 years
    IMO, the temporary variable in @sprinter's answer makes the code more readable (and much more concise). map and orElseGet 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.