我要执行的操作是过滤列表,然后将其映射并在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
?
答案 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。
注意:上述解决方案确实假设emptyMap
为Collections.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
返回Optional
:user -> user.getData().orElse(emptyMap())
方法3:
@Eran所说:Optional.ofNullable
然后像上面这样使用orElse(emptyMap())
:user -> Optional.ofNullable(user.getData()).orElse(emptyMap())
为什么在这种情况下不能使用orElse?
不确定orElse
是什么意思
如果user.getData()
返回null
,则应将其包装到Optional
中以调用orElse
。
流的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
,以避免在nullSafeMap
和Stream::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;
}