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<List<MyEntity>> 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 起作用? map 在 approach 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<List<MyEntity>>
。现在它取决于您使用的 JDK 版本。在JDK8中Optional
没有stream()
方法。
List<MyEntityDto> res = opListEntity.stream() // there is no such method in JDK8
...
由于 JDK9 有一个 stream()
方法,但它当然会返回 Stream<List<MyEntity>>
,因为这是 Optional
的类型。但要使映射工作,您需要Stream<MyEntity>
。为此,您可以使用 flatMap
方法映射返回的流:
List<MyEntityDto> res = opListEntity.stream() // Stream<List<MyEntity>>
.flatMap(List::stream) // Stream<MyEntity>
.map(myEntityMapper::entityToDto)
...
【讨论】:
以上是关于orElseGet 在 Optional<List<Entity>> 的情况下如何工作的主要内容,如果未能解决你的问题,请参考以下文章
IDEA告警详解:Optional.isPresent can be replaced with functional-style expression
IDEA告警详解:Optional.isPresent can be replaced with functional-style expression