java lambda - 如何遍历可选列表/可选流
Posted
技术标签:
【中文标题】java lambda - 如何遍历可选列表/可选流【英文标题】:java lambda - how to traverse optional list/stream of optionals 【发布时间】:2019-01-11 02:07:42 【问题描述】:有一个 Optional 的可选列表:
Optional<List<Optional<String>>> optionalList = Optional.of(
Arrays.asList(
Optional.empty(),
Optional.of("ONE"),
Optional.of("TWO")));
如何遍历optionalList
打印出字符串的ONE
和TWO
?
如果有一个可选的可选流呢?
Optional<Stream<Optional<String>>> optionalStream = Optional.of(
Stream.of(
Optional.empty(),
Optional.of("ONE"),
Optional.of("TWO")));
更新:感谢您的回答, optionalStream 的解决方案(非嵌套):
optionalStream
.orElseGet(Stream::empty)
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println);
【问题讨论】:
到目前为止你有什么尝试? 您也可以只将Optional
映射到Stream
,而不是检查isPresent
并自己明确获取值。会更“实用风格”。
您应该避免将Optional
存储在集合中,请参阅Uses for Optional 和Is it Worth it to Use 'Optional' in Collections?
@DidierL true,但是对于 Stream<Optional<T>>
的情况,这仍然是一个有效的练习,当您的集合中的项目通过其他一些函数映射到 Optional<T>
时,这种练习更为常见,所以你最终得到一个Stream<Optional<T>>
,然后你想要过滤并转换为Stream<T>
。
确实,对我来说这也是一个有效的案例。请注意,Java 9 中引入了 Optional.stream() 方法来避免这种情况(与 flatMap()
结合使用)。最后,我也会避免使用Optional<List>
和Optional<Stream>
,因为它们不太友好。尽可能使用空列表/流,因为这会使 API 更加简洁。
【参考方案1】:
首先,检查Optional
是否存在。如果是,则流式传输列表并过滤非空列表并打印每个列表。
optionalList.ifPresent(list -> list.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println));
流的情况也差不多
optionalStream.ifPresent(stream -> stream
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println));
【讨论】:
添加.map(Optional::get)
将打印字符串【参考方案2】:
如果你可以使用Java 9,可以这样做:
optionalList.ifPresent(list -> list.stream()
.flatMap(Optional::stream)
.forEach(System.out::println));
对于一个可选流,它是相同的,没有第一个 .stream()
调用。
在 Java 8 中,您没有可用的 Optional::stream
方法,因此您可以自己做:
optionalList.ifPresent(list -> list.stream()
.flatMap(opt -> opt.map(Stream::of).orElseGet(Stream::empty))
.forEach(System.out::println));
对于Optional
s 中的Stream
,它看起来像这样:
optionalStream.ifPresent(stream -> stream
.flatMap(opt -> opt.map(Stream::of).orElseGet(Stream::empty))
.forEach(System.out::println));
【讨论】:
尝试了省略第一个.stream()
调用的选项流 - 但不起作用(java 8)
你是什么意思不起作用?刚试了Java 8版本,第一行替换为:optionalStream.ifPresent(stream -> stream
肯定可以。【参考方案3】:
您确实可以流式传输Option<String>
并仅过滤非空值。
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);
您也可以按照其他答案中的建议使用Optional.ifPresent()
:
optionalList.ifPresent(l -> l.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(System.out::println));
我个人更喜欢第一种方式,因为它消除了嵌套级别:我觉得阅读起来更愉快。
【讨论】:
如果列表不存在,第一种方法将创建一个空的ArrayList
。
没错。但是在流执行范围内创建一个空的ArrayList
也没有任何成本。
我手边没有 IDE,但flatMap
不会满足所有isPresent
检查的需求吗?
@chrylis 是的。所有这些答案都太臃肿了,只要将列表中的Optional
项目转换为Stream
和flatMap
即可。【参考方案4】:
我看到有两种方法,第二种对我来说看起来更漂亮,看看:
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】:嗯……
-
检查是否存在可选列表。
对(现在存在的)列表的所有元素执行“for each”。
在每个步骤中检查是否存在可选字符串。
如果是,请打印。
单线可以做到这一点:
optionalList.ifPresent(list -> list.forEach(s -> s.ifPresent(System.out::println)));
【讨论】:
【参考方案6】:optionalList.stream().flatMap(List::stream).filter(Objects::nonNull).forEach(...)
【讨论】:
以上是关于java lambda - 如何遍历可选列表/可选流的主要内容,如果未能解决你的问题,请参考以下文章