Java 8流API或其他用法

时间:2018-12-04 09:28:21

标签: java java-8 java-stream

我要执行的操作是过滤列表,然后将其映射并在orElse中使用null,然后将其收集回列表中。现在,我可以通过以下方式实现它:

return users.stream()
    .filter(user -> id.equals(user.getId()))
    .map(
        user -> {
            if(user.getData() != null) {
                return user.getData();
            }
            return Collections.emptyMap();
        }
    )
    .collect(Collectors.toList());

但是问题是:如何使这种结构更好,为什么在这种情况下我不能使用orElse

5 个答案:

答案 0 :(得分:14)

使用三元条件运算符可能更具可读性:

return users.stream()
    .filter(user -> id.equals(user.getId()))
    .map(
        user -> (user.getData() != null) 
        ? user.getData() 
        : emptyMap()
    )
    .collect(Collectors.toList())
;

要使用orElse,您必须创建一个包装Optional的{​​{1}}。我不确定这是个好主意。

如果您坚持使用user.getData()(或者甚至最好使用orElse,以避免在不需要时评估orElseGet),则它看起来可能像这样:

emptyMap()

答案 1 :(得分:4)

正如我在评论中所指出的那样,我非常怀疑您可能只是在寻找以下内容

users
    .stream()
    .filter(
        user -> id.equals(user.getId()) 
        && (user.getData() != null)
    )
    .map(User::getData)
    .collect(Collectors.toList())
;

但是随后的问题还不够清楚,无法说明语句的最终返回类型是什么,或者代码中使用的emptyMap是什么!因此,我非常怀疑,该操作是否首先需要使用Optional API。

注意:上述解决方案确实假设emptyMapCollections.emptyMap,但我不确定为什么要收集在表示为List<Map<K,V>>的数据结构中。 / p>

答案 2 :(得分:1)

  

如何使这种结构更好

方法1:

return users.stream()
    .filter(user -> id.equals(user.getId()))
    .map(
        user -> (user.getData() != null)
        ? user.getData() 
        : emptyMap()
    )
    .collect(Collectors.toList())
;

方法2:

让您的getData返回Optionaluser -> user.getData().orElse(emptyMap())

方法3:

@Eran所说:Optional.ofNullable然后像上面这样使用orElse(emptyMap())user -> Optional.ofNullable(user.getData()).orElse(emptyMap())

  

为什么在这种情况下不能使用orElse?

不确定orElse是什么意思

  1. 如果user.getData()返回null,则应将其包装到Optional中以调用orElse

  2. 流的findAny().orElse对流的结果本身进行操作。但是,这里您需要检查user.getData()是否存在。因此,您不能直接使用流结果的orElse

答案 3 :(得分:1)

使用Objects::requireNonNullElse

我建议通过两件事来使代码更具可读性。但是,我不会人为地引入Optional


第一个选项:Objects::requireNonNullElse在单独的方法中

List<Map<?, ?> bar() {
    //...

    return users.stream()
                .filter(user -> id.equals(user.getId()))
                .map(User::getData)
                .map(Foo::nullSafeMap)
                .collect(Collectors.toList());
}

private static Map<?, ?> nullSafeMap(final Map<?, ?> map) {
    return Objects.requireNonNullElse(map, Collections.emptyMap());
}

在这里,您将使用Objects::requireNonNullElse,如果不是null,它将返回第一个参数传递的对象,如果第一个参数是{{1},则返回第二个参数传递的对象。 }。拥有单独的方法可以将方法引用传递给null,但是需要您首先将Stream::map实例映射到其数据User


第二个选项:内联Map

Objects::requireNonNullElse

如果您不希望单独的方法仅执行单个任务,则可以内联该方法,甚至可以选择删除第一个映射,而推荐使用List<Map<?, ?> bar() { //... return users.stream() .filter(user -> id.equals(user.getId())) .map(User::getData) .map(map -> Objects.requireNonNullElse(map, Collections.emptyMap())) .collect(Collectors.toList()); } ,但我建议您不要这样做。如果这样会使代码更具可读性,请不要害怕多次调用.map(user -> Objects.requireNonNullElse(user.getData(), Collections.emptyMap()))


结论

我会首选第一个选项,因为它使代码更具可读性:您知道将Stream::map实例映射到数据,然后使该数据为null安全。

第二个选项还不错,但是乍一看可能会很长。但是,它比具有多行lambda更好。 我会不惜一切代价避免使用多行lambda,并始终将其内容提取到单独的方法中。

您可能需要改进的一件事是方法名称User,以避免在nullSafeMapStream::map之间造成混淆。

请注意,您不需要使用Objects::requireNonNullElseGet,因为java.util.Map是一种仅转换并返回常量的轻量级方法:

Collections::emptyMap

public static final <K,V> Map<K,V> emptyMap() { return (Map<K,V>) EMPTY_MAP; } 用于获取或创建重量级对象的默认对象。

答案 4 :(得分:0)

如果您已经拥有Apache Collections 4作为依赖项:

return users
    .stream()
    .filter(user -> id.equals(user.getId()))
    .map(User::getData)
    .map(MapUtils::emptyIfNull)
    .collect(Collectors.toList())
;

如果您不使用Apache集合,只需定义一个辅助方法:

public static <K,V> Map<K,V> emptyIfNull(Map<K,V> map) {
    return map == null ? Collections.<K,V>emptyMap() : map;
}