20

I need to remove all empty/null values from List<Optional<String>>.

Example:

List<Optional<String>> list = new ArrayList<>();

list.add(Optional.empty());
list.add(Optional.of("Str1"));
list.add(Optional.of("Str2"));
list.add(Optional.of("Str3"));
list.add(Optional.of("Str4"));
list.add(Optional.of("Str5"));
list.add(Optional.empty());
list.add(Optional.ofNullable(null));

Currently, I'm using one of the below approaches:

Way 1:

List<String> collect = list.stream()
                   .filter(Optional::isPresent)
                   .map(obj ->obj.get())
                   .collect(Collectors.toList());

Way 2:

List<Optional<String>> emptlist = new ArrayList<>();
emptlist.add(Optional.empty());
list.removeAll(emptlist);

Is there any other better way?

4
  • 3
    Do you want to create a filtered copy of the list and transform optionals to Strings, or to remove empty elements from the list? Option 1 does the former, Option 2 does the latter. So they don't do the same thing at all. If the latter, using removeIf() would be much clearer. Commented Dec 29, 2017 at 10:01
  • 4
    What is the question exactly ? But use Collection.removeIf. Simply like list.removeIf(o -> !o.isPresent()); Commented Dec 29, 2017 at 10:14
  • 2
    Your edit doesn't really help (I was able to read that before), you are still not clear, first you ask to "remove all empty/null values from List<Optional<String>>." then you said in comments "-need separate copy of filtered list". So what is it ? Please provide a minimal reproducible example explaining what you expect. Commented Dec 29, 2017 at 10:50
  • 2
    see Filtering a Stream of Optionals in Java. Also, IMO the first approach is as clean as it gets with java-8 though you could do map(Optional::get) rather than map(obj ->obj.get()). Commented Dec 29, 2017 at 10:55

3 Answers 3

27

With Java9, you can do this using the newly added Optional::stream API :

List<String> collect = list.stream()
               .flatMap(Optional::stream)
               .collect(Collectors.toList());

This method can be used to transform a Stream of optional elements to a Stream of present value elements.

Sticking with Java8, the Way1 in the question is good enough IMHO -

List<String> collect = list.stream()
               .filter(Optional::isPresent)
               .map(Optional::get) // just a small update of using reference
               .collect(Collectors.toList());
Sign up to request clarification or add additional context in comments.

Comments

8

removeIf is the shortest way to do that :

list.removeIf(x -> !x.isPresent());

2 Comments

only if that list supports removal
@Eugene: that’s implied by the OP’s second variant using removeAll. But even that can be simplified to a single liner: list.removeAll(List.of(Optional.empty()));
1

For anyone who wants to have a little fun or understand working of Optionals and Streams better (Java 8):

List<String> collect=list.stream().
                                   map(z->z.map(Stream::of)).
                                   flatMap(ox->ox.orElseGet(Stream::empty)).
                                   collect(Collectors.toList());
  1. The first map function converts Optional[String] to Optional [Stream[String]]. A Stream String[Optional [Stream[String]]] is thus passed forward
  2. The "map" part of flatmap converts each Optional[Stream[String]] to Stream[String]. All empty Optionals are replaced by an empty Stream. Now we have Stream[Stream[String]].
  3. The "flat" part converts Stream[Stream[String]] to Stream[String].

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.