问题
Having an Optional List of Optional's like:
Optional<List<Optional<String>>> optionalList = Optional.of(
Arrays.asList(
Optional.empty(),
Optional.of("ONE"),
Optional.of("TWO")));
How to traverse optionalList to print out the string's ONE and TWO ?
What about having an Optional Stream of Optionals?
Optional<Stream<Optional<String>>> optionalStream = Optional.of(
Stream.of(
Optional.empty(),
Optional.of("ONE"),
Optional.of("TWO")));
Update: Thanks for answers, solution for optionalStream (non nested):
optionalStream
.orElseGet(Stream::empty)
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println);
回答1:
First, check if the Optional is present. If yes, then stream the list and filter the non-empty ones and print each of them.
optionalList.ifPresent(list -> list.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println));
Almost similar for the stream case too
optionalStream.ifPresent(stream -> stream
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println));
回答2:
You can indeed stream the Option<String> and filter only non empty values.
Optional<List<Optional<String>>> optionalList = Optional.of(Arrays.asList(Optional.empty(), Optional.of("ONE"), Optional.of("TWO")));
optionalList.orElseGet(ArrayList::new)
.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println);
You can also use Optional.ifPresent() as suggested in another answers :
optionalList.ifPresent(l -> l.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println));
Personally I prefer the first way because it removes a nested level : I find it more pleasant to read.
回答3:
If you can use Java 9, it can be done like this:
optionalList.ifPresent(list -> list.stream()
.flatMap(Optional::stream)
.forEach(System.out::println));
For a stream of optionals it would be the same, without the first .stream() call.
With Java 8 you don't have the Optional::stream method available so you can do it yourself:
optionalList.ifPresent(list -> list.stream()
.flatMap(opt -> opt.map(Stream::of).orElseGet(Stream::empty))
.forEach(System.out::println));
And for a Stream of Optionals it would look like this:
optionalStream.ifPresent(stream -> stream
.flatMap(opt -> opt.map(Stream::of).orElseGet(Stream::empty))
.forEach(System.out::println));
回答4:
As I see there are two ways, second one look a bit more pretty to me, take a look:
class Scratch {
public static void main(String[] args) {
Optional<String> element1 = Optional.of("test1");
Optional<String> element2 = Optional.empty();
Optional<String> element3 = Optional.of("test2");
Optional<String> element4 = Optional.of("test3");
List<Optional<String>> list = Arrays.asList(element1, element2, element3, element4);
System.out.println(extractStrings1(list));
System.out.println(extractStrings2(list));
}
private static List<String> extractStrings1(List<Optional<String>> list) {
return list.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
}
private static List<String> extractStrings2(List<Optional<String>> list) {
List<String> result = new ArrayList<>();
list.forEach(element -> element.ifPresent(result::add));
return result;
}
}
回答5:
Well ...
- Check whether the optional list is present.
- Do a "for each" for all elements of the (now present) list.
- In each step check whether the optional string is present.
- If yes, print it.
A one-liner can do that:
optionalList.ifPresent(list -> list.forEach(s -> s.ifPresent(System.out::println)));
来源:https://stackoverflow.com/questions/51668246/java-lambda-how-to-traverse-optional-list-stream-of-optionals