Java Stream去重常见的多种方法及示例
目录
- 1. 使用 distinct() 方法
- 2. 根据对象的属性去重
- 方法一:使用 Collectors.toMap
- 方法二:使用 filter 和线程安全的 Set
- 方法三:使用 groupingBy
- 3. 根据字符串长度去重示例
- 4. 自定义去重借助Filter 实现:
- 附:Java中使用stream流根据对象中的某一字段进行去重
- 总结
在Java Stream中实现去重有多种方法,具体取决于需求和场景。以下是常见的几种方法及示例:
1. 使用 distinct() 方法
适用于对象已正确实现 equals()
和 hashCode()
,基于对象整体去重并保留顺序:
List<Person> uniquePersons = persons.stream() .distinct() .collect(Collectors.toList());
2. 根据对象的属性去重
方法一:使用 Collectors.toMap
根据属性作为键,保留第一个或最后一个元素,支持顺序(使用 LinkedHashMap
):
// 保留第一个出现的元素 List<Person> uniqueByName = persons.stream() .collect(Collectors.toMap( Person::getName, Function.identity(), (oldP, newp) -> oldP, // 保留旧值(第一个) LinkedHashMap::new // 保持插入顺序 )) .values().stream() .collect(Collectors.toList()); // 保留最后一个出现的元素 List<Person> uniqueByNameLast = persons.stream() .collect(Collectors.toMap( Person::getName, Function.identity(), (oldP, newP) -> newP // 保留新值(最后一个) )) .values().stream() .collect(Collectors.toList());
方法二:使用 filter 和线程安全的 Set
适用于并行流,但可能不保留顺序:
// 并行流去重(不保证顺序) Set<String> seen = ConcurrentHashMap.newKeySet(); List<Person> uniqueByName = persons.parallelStream() .filter(p -> seen.add(p.getName())) .collect(Collectors.toList()); // 顺序流去重(保留顺序) Set<String> seenOrdered = new HashSet<>(); List<Person> uniqueByNameOrdered = persons.stream() .filter(p -> seenOrdered.add(p.getName())) .collect(Collectors.toList());
方法三:使用 groupingBy
分组后取每组的第一个元素,保持顺序:
List<Person> uniqueByName = persons.stream() .collect(Collectors.groupingBy( Perwww.devze.comson::getName, LinkedHashMap::new, // 保持插入顺序 Collectors.toList() )) .values().stream() .map(group -> group.get(0)) // 取第一个元素 .collect(Collectors.toList());
3. 根据字符串长度去重示例
List<String> words = Arrays.asList("apple", "banana", "orange", "grape", "kiwi"); List<String> uniqueByLength = words.stream() .collect(Collectors.toMap( 编程客栈 String::length, Function.identity(), (oldVal, newVal) -> oldVal, LinkedHashMap::new )) .values().stream() .collect(Collectors.toList()); // 结果: ["apple", "bananandroida", "kiwi"](保留顺序)
4. 自定义去重借助Filter 实现:
自定义一个 Predicate 函数,用一个 Set 来记录已经出现过的元素,然后过滤掉重复的元素。
//定义一个Predicate函数 private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) { Set<Object> sets = ConcurrentHashMap.newKeySet(); return t -> sets.add(keyExtractor.apply(t)); } //根据age属性去重 list.stream().filter(distinctByKey(s -> s.getAge())) .forEach(System.out::println);
附:java中使用stream流根据对象中的某一字段进行去重
在开发中经常会遇到数据去重的,单个基本类型的集合去重比较容易,比如String、Integer,直接使用流中的distinct方法去重即可。但是遇到对象集合,需编程客栈要使用对象中的某个字段去重就不能使用这个方法了。可以在流式编程中加入TreeSet,TreeSet是一个有序且不重复的有序集合。以用户User数据位列:
List<User> list = userService.list(); list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing( f -> f.getDeptName()+":"+f.getStatus()))),ArrayList::new));
这里是根据用户的部门以及用户的状态进行数据去重,将用户的部门以及状态拼接位一个字符串进行去重,这样stream内部会将整个user集合数据组装成这样进行整体去重,这样去重下来的数据就是,每一个部门中只会存在一个状态的部门人员数据,这里是举个例子,在实际环境中,你可以将User换成自己想要去重的实体集合。
总结
distinct()
:简单高效,适用于对象整体去重。toMap
或&nbsjsp;groupingBy
:灵活,支持按属性去重,可控制保留顺序。filter
+Set
:适合并行流,但需注意线程安全和顺序问题。
根据具体场景选择最合适的方法,确保代码简洁且性能良好。
到此这篇关于Java Stream去重常见的多种方法及示例的文章就介绍到这了,更多相关Java Stream去重方法内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论