本文翻译自:Java 8 Distinct by property

In Java 8 how can I filter a collection using the Stream API by checking the distinctness of a property of each object? 在Java 8中,如何通过检查每个对象的属性的不同性来使用Stream API过滤集合?

For example I have a list of Person object and I want to remove people with the same name, 例如,我有一个Person对象的列表,我想删除同名的人,

persons.stream().distinct();

Will use the default equality check for a Person object, so I need something like, 将对Person对象使用默认的相等性检查,所以我需要类似的东西,

persons.stream().distinct(p -> p.getName());

Unfortunately the distinct() method has no such overload. 不幸的是, distinct()方法没有这样的重载。 Without modifying the equality check inside the Person class is it possible to do this succinctly? 如果不修改Person类内部的相等性检查,是否可以简洁地做到这一点?


#1楼

参考:https://stackoom.com/question/1bRHv/Java-按属性区分


#2楼

You can wrap the person objects into another class, that only compares the names of the persons. 您可以将人员对象包装到另一个类中,该类仅比较人员的名称。 Afterwards, you unwrap the wrapped objects to get a person stream again. 然后,您解开包装的对象以再次获得人流。 The stream operations might look as follows: 流操作可能如下所示:

persons.stream().map(Wrapper::new).distinct().map(Wrapper::unwrap)...;

The class Wrapper might look as follows: Wrapper类可能如下所示:

class Wrapper {private final Person person;public Wrapper(Person person) {this.person = person;}public Person unwrap() {return person;}public boolean equals(Object other) {if (other instanceof Wrapper) {return ((Wrapper) other).person.getName().equals(person.getName());} else {return false;}}public int hashCode() {return person.getName().hashCode();}
}

#3楼

An alternative would be to place the persons in a map using the name as a key: 一种替代方法是使用姓名作为关键字将人员放置在地图中:

persons.collect(toMap(Person::getName, p -> p, (p, q) -> p)).values();

Note that the Person that is kept, in case of a duplicate name, will be the first encontered. 请注意,如果姓名重复,则被保住的人将是第一个进入的人。


#4楼

The easiest way to implement this is to jump on the sort feature as it already provides an optional Comparator which can be created using an element's property. 实现此功能的最简单方法是跳过排序功能,因为它已经提供了一个可选的Comparator ,可以使用元素的属性创建它。 Then you have to filter duplicates out which can be done using a statefull Predicate which uses the fact that for a sorted stream all equal elements are adjacent: 然后,您必须过滤掉重复项,这可以使用statefull Predicate来完成,该Predicate使用以下事实:对于已排序的流,所有相等的元素都是相邻的:

Comparator<Person> c=Comparator.comparing(Person::getName);
stream.sorted(c).filter(new Predicate<Person>() {Person previous;public boolean test(Person p) {if(previous!=null && c.compare(previous, p)==0)return false;previous=p;return true;}
})./* more stream operations here */;

Of course, a statefull Predicate is not thread-safe, however if that's your need you can move this logic into a Collector and let the stream take care of the thread-safety when using your Collector . 当然,有状态的Predicate不是线程安全的,但是,如果您有此需要,则可以将此逻辑移到Collector并在使用Collector时让流负责线程安全。 This depends on what you want to do with the stream of distinct elements which you didn't tell us in your question. 这取决于您要如何处理不同的元素流,而您没有在问题中告诉我们这些元素。


#5楼

Consider distinct to be a stateful filter . 认为distinct是有状态过滤器 Here is a function that returns a predicate that maintains state about what it's seen previously, and that returns whether the given element was seen for the first time: 这是一个函数,该函数返回一个谓词,该谓词保持先前状态的状态,并返回是否第一次看到给定的元素:

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {Set<Object> seen = ConcurrentHashMap.newKeySet();return t -> seen.add(keyExtractor.apply(t));
}

Then you can write: 然后您可以编写:

persons.stream().filter(distinctByKey(Person::getName))

Note that if the stream is ordered and is run in parallel, this will preserve an arbitrary element from among the duplicates, instead of the first one, as distinct() does. 请注意,如果流是有序的并并行运行,则这将保留重复项中的任意元素,而不是像distinct()那样保留第一个元素。

(This is essentially the same as my answer to this question: Java Lambda Stream Distinct() on arbitrary key? ) (这基本上与我对以下问题的回答相同: 任意键上的Java Lambda Stream Distinct()? )


#6楼

There's a simpler approach using a TreeSet with a custom comparator. 将TreeSet与自定义比较器一起使用是一种更简单的方法。

persons.stream().collect(Collectors.toCollection(() -> new TreeSet<Person>((p1, p2) -> p1.getName().compareTo(p2.getName()))
));

Java 8按属性区分相关推荐

  1. java中蛇的属性有哪些_学习Java类的属性

    学习Java类的属性-武汉北大青鸟 Public.private.protected显示了三种类中的属性和服务的类型,public是可以随意访问的.private是外界不能访问的(显示了数据的封装性) ...

  2. 【java】java获取对象属性类型、属性名称、属性值

    java获取对象属性类型.属性名称.属性值 获取属性 修饰符:[在Field[]循环中使用] String modifier = Modifier.toString(fields[i].getModi ...

  3. 除了数据属性,Vue 实例还提供了一些有用的实例属性与方法。它们都有前缀 $,以便与用户定义的属性区分开来。

    实例 <div id="vue_det"> <h1>site : {{site}}</h1> <h1>url : {{url}}&l ...

  4. Linux中的Java类,Java基础入门学习-Java中类的属性

    Java基础入门学习-Java中类的属性 发布时间:2006-05-27 00:46:15来源:红联作者:WWW Public.private.protected显示了三种类中的属性和服务的类型,pu ...

  5. Java使用对象使用属性过滤集合对象重复数据

    使用流Stream方式过滤对象中重复的数据-Java使用对象使用属性过滤集合对象重复数据 1.先创建一个方法工具类 private static <T> Predicate<T> ...

  6. java遍历一个类的属性名,java遍历对象属性

    java对象动态添加属性,Class对象和Java反射机制,java遍历对象属性,js对象动态添加属性 java 对象动态添加属性,Class对象和Java反射机制,java遍历对象属性,js对象动态 ...

  7. 如何配置数据库带有下划线字段对应Java实体类属性(驼峰命名)

    一般开发中,数据库字段设计推荐使用下划线(u_name),Java实体类属性使用驼峰命名(uName),为了能使数据库字段与Java实体类属性一一映射,需要做一下的配置,这里我用的是spring bo ...

  8. java中私有属性能不能被继承?

    java中私有属性能不能被继承? 以前的课堂中,老师讲继承的时候说过:子类可以继承父类中的属性和方法.可是当我们写代码的时候却能出现一些不一样的情况. 其原因在什么地方?之后通过代码的验证发现出现在了 ...

  9. java获取object属性值_java反射获取一个object属性值代码解析

    有些时候你明明知道这个object里面是什么,但是因为种种原因,你不能将它转化成一个对象,只是想单纯地提取出这个object里的一些东西,这个时候就需要用反射了. 假如你这个类是这样的: privat ...

最新文章

  1. linux apache 查看mpm 配置方式,Apache MPM模块prefork和worker的区别与配置
  2. Java I/O在Android中应用(一)
  3. 大工18秋计算机应用在线作业,大工18秋《计算机组网技术》在线测试1【标准答案】...
  4. python linux教程_在RedHat系统Linux上部署Python的Celery框架的教程
  5. linux中安装,编译时调用,运行时调用,更新共享库
  6. 第五次作业 第三章例题
  7. 英语本科 国外跨计算机,跨专业考研需具备哪些条件,如英语,计算机的过级情况...
  8. 微信登录界面安卓代码_安卓Activity劫持与反劫持
  9. 谷歌多账号 桌面快捷方式
  10. JavaScript函数开关思想
  11. linux系统的系统命令大全,linux系统命令大全
  12. 扇贝单词里有计算机英语吗,扇贝单词记录
  13. 什么是预付卡及预付卡发展前景
  14. MIUI黑科技之小米直达服务:Web 般的流畅体验+更少的卡顿、延迟
  15. 五个常用计算机应用软件6,信息技术应用--常用计算机工具软件5常用工具软件单元五.pdf...
  16. Win11首个预览版来了!附升级方法
  17. 2021年全球衍射光栅收入大约227.4百万美元,预计2028年达到325.6百万美元
  18. CentOS 8 中安装配置FreeRADIUSDaloRADIUS以及为不同SSID验证MAC等
  19. Scaffold-DbContext 报“未能加载文件或程序集“netstandard”的解法
  20. 《鸟哥Linux私房菜》读书笔记0\1\2\3\4章

热门文章

  1. observeOn()与subscribeOn()的详解
  2. Android 探究 LayoutInflater setFactory
  3. 专业程序员成长之路之基础基础!
  4. repo file=sys.stderr 错误解决
  5. 批量启动关闭MS SQL 2005服务BAT
  6. join,和循环删除,fromkeys,集合,拷贝
  7. 01Python基础_09异常
  8. ubuntu下制作u盘启动盘
  9. PGA_AGGREGATE_TARGET 原理
  10. 【软件】chrome设置默认字体