orElseGet 在 Optional<List<Entity>> 的情况下如何工作

Posted

技术标签:

【中文标题】orElseGet 在 Optional<List<Entity>> 的情况下如何工作【英文标题】:How does orElseGet work in case of an Optional<List<Entity>> 【发布时间】:2021-12-27 01:19:01 【问题描述】:

我有一个类的可选列表,即:Optional&lt;List&lt;MyEntity&gt;&gt; opListEntity

当存在 Optional 时,我需要将所有 MyEntity 映射到 MyEntityDto。如果 Optional 为空,我将返回一个空的 ArrayList

方法 1(非功能性):

注意:myEntityMapper 是映射器类的对象,它将MyEntity 映射到MyEntityDto

List<MyEntityDto> res;
if (opListEntity.isPresent()) 
       res = opListEntity.get().stream()
            .map(myEntityMapper::entityToDto)
            .collect(Collectors.toList());
 else 
       res = new ArrayList<>();

这种方法很好,但 IntelliJ 建议将其转换为函数式表达式。我让 IntelliJ 进行转换,这就是我得到的:

方法二(函数表达式):

List<MyEntityDto> res = opListEntity.map(myEntities -> myEntities.stream()
            .map(myEntityMapper::entityToDto)
            .collect(Collectors.toList()))
     .orElseGet(ArrayList::new);

我不明白的是,在方法 2 @ line 1 中,为什么会有地图?

让我再解释一下。见第三种方法:

方法3:

List<CustomerAddressEntity> myEntities = opListEntity
        .orElseGet(ArrayList::new);
List<MyEntityDto> res = myEntities.stream()
        .map(myEntityMapper::entityToDto)
        .collect(Collectors.toList());

方法 3 工作正常,但如果我尝试将方法 3 转换为方法 4,它就不起作用了。

方法4:

List<MyEntityDto> res = opListEntity.stream()
            .map(myEntityMapper::entityToDto)
            .collect(Collectors.toList()))
     .orElseGet(ArrayList::new);

为什么方法 4 不起作用,而 方法 2 起作用? mapapproach 2 @ line 1 中做了什么?

【问题讨论】:

因为您需要双重展开项目,可选的列表和列表中的项目。即在 4 中你需要 flatMap. 没有充分的理由将 List 包装在 Optional 中。如果 List 没有项目,就让它成为一个空 List。 @DavidConrad 是的,你是对的,但该代码是由其他人编写的,我无法修改。 "我不明白的是,在第 1 行的方法 2 中,为什么会有地图?"您还期望如何与 Optional 进行交互? @VLAZ 抱歉,我对 Optional map() & Stream map() 感到困惑。我之前没有使用过可选的地图,我把它误认为是 Stream map()。这就是为什么这个天真的问题。但是在阅读了下面的答案后,事情就解决了。 【参考方案1】:

我认为如果您将代码缩进一点以使其更容易发现,就会变得很明显:

List<MyEntityDto> res = opListEntity // Optional<List<MyEntity>>
    .map(
        myEntities -> myEntities.stream() // Stream<MyEntity>
            .map(myEntityMapper::entityToDto)  // Stream<MyEntityDto>
            .collect(Collectors.toList()) // List<MyEntityDto>
        )
    .orElseGet(ArrayList::new); // List<MyEntityDto>

Optional(如果存在)映射到将包含的列表转换为流、映射元素并构建集合或(如果为空)到新的空列表的结果。

在您的第 4 种方法中,opListEntity 的类型为 Optional&lt;List&lt;MyEntity&gt;&gt;。现在它取决于您使用的 JDK 版本。在JDK8中Optional没有stream()方法。

List<MyEntityDto> res = opListEntity.stream() // there is no such method in JDK8
    ...

由于 JDK9 有一个 stream() 方法,但它当然会返回 Stream&lt;List&lt;MyEntity&gt;&gt;,因为这是 Optional 的类型。但要使映射工作,您需要Stream&lt;MyEntity&gt;。为此,您可以使用 flatMap 方法映射返回的流:

List<MyEntityDto> res = opListEntity.stream() // Stream<List<MyEntity>>
    .flatMap(List::stream) // Stream<MyEntity>
    .map(myEntityMapper::entityToDto)
...

【讨论】:

以上是关于orElseGet 在 Optional<List<Entity>> 的情况下如何工作的主要内容,如果未能解决你的问题,请参考以下文章

java Optional null判断不再那么丑陋

Java8特性:Optional空值处理

Java8特性:Optional空值处理

IDEA告警详解:Optional.isPresent can be replaced with functional-style expression

IDEA告警详解:Optional.isPresent can be replaced with functional-style expression

Swift3,展开 Optional<Binding>(在 SQLite.swift 中)