我想要的建议是通过某个内部对象的字段过滤列表。 因此,我在互联网上找到了一种方法,就像这样:
public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
然后,我这样使用
list.stream().filter(LambdaUtils.distinctByKey(o -> o.getLogisticsNumber() == null ? o.getId() : o.getLogisticsNumber())).collect(Collectors.toList());
它工作正常,但是我想尝试一些不同的东西,所以我更改代码而不使用函数,而不是代码。
list.stream().filter(
x -> {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
Function<DeliveryOrderItemMaterialLogisticInfo ,Object> keyExtractor = o -> o.getLogisticsNumber() == null ? o.getId() : o.getLogisticsNumber();
return seen.putIfAbsent(keyExtractor.apply(x), Boolean.TRUE) == null;
}
).collect(Collectors.toList());
那么结果就是错误。
为什么?两者之间有什么不同?
答案 0 :(得分:0)
在第二个代码版本中:
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
为每个元素Map<> seen
初始化了映射x
,因此您的过滤器始终返回true
,这将允许所有元素通过。
将Map<> seen
声明移至lambda外部将更正您的用法。
在第一个代码版本中,Map<> seen
仅被初始化。它返回的只是一个谓词:
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
将该谓词传递到流中时,它不会创建新的Map
,而是使用之前声明的引用Map<> seen
。