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

Him*_*bas 3 java functional-programming java-stream

我有一个类的可选列表,即:Optional<List<MyEntity>> opListEntity

我需要将所有映射MyEntityMyEntityDto可选存在时。如果Optional为空,我将返回一个空的ArrayList


方法 1(非功能性):

注意:myEntityMapper是一个映射器类的对象,它映射MyEntityMyEntityDto.

List<MyEntityDto> res;
if (opListEntity.isPresent()) {
       res = opListEntity.get().stream()
            .map(myEntityMapper::entityToDto)
            .collect(Collectors.toList());
} else {
       res = new ArrayList<>();
}
Run Code Online (Sandbox Code Playgroud)

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

方法2(函数表达式):

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

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

让我再解释一下。请参阅第三种方法:

方法三:

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

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

方法四:

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

为什么方法4不起作用而方法2却有效? 方法 2 @ 第 1 行中的
额外地图在做什么?

dpr*_*dpr 9

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

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>
Run Code Online (Sandbox Code Playgroud)

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

在你的第四种方法中,opListEntity类型是Optional<List<MyEntity>>。现在这取决于您使用的 JDK 版本。在JDK8中Optional没有stream()方法。

List<MyEntityDto> res = opListEntity.stream() // there is no such method in JDK8
    ...
Run Code Online (Sandbox Code Playgroud)

从 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)
...
Run Code Online (Sandbox Code Playgroud)