使用 Stream 去重
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StreamDistinctTest {
private Long id;
private Long userId;
private String username;
private String address;
public static void main(String[] args) {
List<StreamDistinctTest> listTest = Lists.newArrayList();
listTest.add(new StreamDistinctTest(1L, 1L, "test", "aa"));
listTest.add(new StreamDistinctTest(2L, 3L, "test", "bb"));
listTest.add(new StreamDistinctTest(3L, 1L, "test3", "cc"));
listTest.add(new StreamDistinctTest(4L, 3L, null, "dd"));
// 按照 userId 对集合去重
List<StreamDistinctTest> collect = listTest.stream().filter(distinctByKey(StreamDistinctTest::getUserId)).collect(Collectors.toList());
System.out.println(JSON.toJSONString(collect));
// 若后续使用的集合只是用到了对象中的一个值(如:关联的 userId, 然后根据userId查询),可以直接使用 map() 取出后再过滤
List<Long> collect2 = listTest.stream().map(StreamDistinctTest::getUserId).distinct().collect(Collectors.toList());
System.out.println(JSON.toJSONString(collect2));
// 若过滤的属性有可能为 null,需要先去除,否则 distinctByKey() 会抛 NPE
List<StreamDistinctTest> collect3 =
listTest.stream().filter(user -> StringUtils.isNotBlank(user.getUsername())).filter(distinctByKey(StreamDistinctTest::getUsername)).collect(Collectors.toList());
System.out.println(JSON.toJSONString(collect3));
}
/**
* @param keyExtractor
* @param <T>
* @return
*/
private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> setView = ConcurrentHashMap.newKeySet();
return t -> setView.add(keyExtractor.apply(t));
// 使用 map
// Map<Object, Boolean> map = new ConcurrentHashMap<>(16);
// return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
}
Collector.toMap()
使用 stream 将 List 转 Map 时, 有重复 key 出现,报错
Map<Integer, String> collect = listData.stream().collect(Collectors.toMap(TestDemo::getCode, TestDemo::getContent));
解决方案:使用 toMap() 重载方法,第三个参数:mergeFunction
/**
* @param mergeFunction a merge function, used to resolve collisions between
* values associated with the same key, as supplied
* to {@link Map#merge(Object, Object, BiFunction)}
*/
Map<Integer, String> collect = listData.stream().collect(Collectors.toMap(TestDemo::getCode,
TestDemo::getContent, (oldValue, newValue) -> oldValue));
注:Collectors.toConcurrentMap() 也有同样问题