仅过滤 Collection 中的唯一元素
扫码关注《Java学研大本营》,加入读者群,分享更多精彩
介绍
-
当我们从一台机器到另一台机器交换数据时,重复条目是非常常见的问题。
-
作为客户端,在使用这些记录时,我们必须实现一个逻辑来处理这些重复记录。
-
在本博客中,我们将了解如何在 Java 中处理重复项。
用例
-
我们将以我们提供的客户列表和 emailId 为例。我们的主要目标是从中过滤掉不同的记录。
// list of emailId
List<String> emailList = List.of("abc@gmail.com", "pqr@gmail.com", "tuf@gmail.com", "lth@gmail.com", "abc@gmail.com");
// list of emailId
List<Customer> customers = List.of(new Customer(1, 23,"abc@gmail.com"),new Customer(2, 25,"xbc@gmail.com"),new Customer(1, 23,"abc@gmail.com"));
使用哈希集
-
首先我们将使用Hashset 数据结构。如果你不知道,hashset 只包含唯一元素,如果你尝试添加两次相同的元素,hashset 将返回 false。
-
所以我们保证在 hashset 中有唯一的元素。
-
在下面的示例中,我们正在迭代每个 emailId 并添加到我们的集合中。 完成后,我们从这个集合中创建一个不同的列表。
List<String> emailList = List.of("abc@gmail.com", "pqr@gmail.com", "tuf@gmail.com", "lth@gmail.com", "abc@gmail.com");
emailList.stream().forEach(a-> System.out.println(a));
System.out.println("==========================");
// using hashset
HashSet<String> set = new HashSet<>();
for ( String emailId: emailList ) {
set.add(emailId);
}
emailList = new ArrayList<>(set);
emailList.stream().forEach(a-> System.out.println(a));
-
现在我们有了唯一的 emailId 列表。我们可以通过打印来检查。
-
如我们所见,我们重复的 emailId 已从原始电子邮件列表中过滤掉。
使用不同的方法
-
我们可以使用的其他方法是来自Streams API 的 in-build distinct() 方法。(https://medium.com/javarevisited/7-best-java-tutorials-and-books-to-learn-lambda-expression-and-stream-api-and-other-features-3083e6038e14?source=---------14------------------)
-
让我们从列表创建 Stream并执行 distinct() 操作以仅过滤掉唯一元素。(https://javarevisited.blogspot.com/2014/03/2-examples-of-streams-with-Java8-collections.html)
List<String> emailList = List.of("abc@gmail.com", "pqr@gmail.com", "tuf@gmail.com", "lth@gmail.com", "abc@gmail.com");
emailList.stream().forEach(a-> System.out.println(a));
System.out.println("==========================");
// streams api
List<String> distinctEmailList = emailList.stream().distinct().collect(Collectors.toList());
distinctEmailList.stream().forEach(a-> System.out.println(a));
-
现在我们可以通过打印我们不同的电子邮件列表来进行测试。
-
到目前为止,我们一直在过滤 Primitive 类型,但接下来我们将使用自定义对象类型,我们将删除重复的对象。
客户 POJO
-
让我们首先创建自定义类 Customer,它只是 POJO。
import java.util.Objects;
public class Customer {
private int id;
private int age;
private String emailId;
public Customer(int id, int age, String emailId) {
this.id = id;
this.age = age;
this.emailId = emailId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
@Override
public String toString() {
return "Customer{" +
-
现在让我们通过创建客户对象来创建示例客户列表。
-
现在避免使用 api流 distinct() 方法并检查它是否也在对象上工作。
List<Customer> customers = List.of(new Customer(1, 23,"abc@gmail.com"),
new Customer(2, 25,"xbc@gmail.com"),
new Customer(1, 23,"abc@gmail.com"));
customers.stream().forEach(a-> System.out.println(a));
System.out.println("==========================");
customers.stream().distinct().forEach(a-> System.out.println(a));
-
但是当我们 print 时,我们发现它不是真的。它仍然打印重复的客户。
-
这意味着 distinct 不适用于自定义类型?
-
造成这种情况的主要原因不是 distinct() 方法的问题,而是hashcode 和 equals 方法的问题。(https://javarevisited.blogspot.com/2013/08/10-equals-and-hashcode-interview.html)
-
我们必须在我们之前创建的Customer POJO 中覆盖equals方法和hashcode方法。
-
正如我们所看到的,我们正在比较客户类的每个属性,在hashcode中,我们使用客户类属性来计算 hashcode 。(https://javarevisited.blogspot.com/2011/02/how-to-write-equals-method-in-java.html)
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Customer customer = (Customer) o;
return id == customer.id && age == customer.age && emailId.equals(customer.emailId);
}
@Override
public int hashCode() {
return Objects.hash(id, age, emailId);
}
-
一旦我们添加了 hashCode 和 equals 方法,那么我们在流上的 distinct 方法将起作用。
-
我们可以看到过滤掉重复值的结果。
哈希集
-
我们还可以使用我们用于原始过滤的HashSet 。(https://www.java67.com/2014/01/when-to-use-linkedhashset-vs-treeset-vs-hashset-java.html)
HashSet<Customer> set = new HashSet<>();
customers.stream().forEach(a->set.add(a));
ArrayList<Customer> distinctCustomers = new ArrayList<>(set);
distinctCustomers.stream().forEach(a-> System.out.println(a));
-
这是结果。
结论
-
在这篇博客中,我们看到了 Java 中从元素列表中过滤出唯一元素的各种方法。
-
我们讨论了使用 Hashset 和流 api 来实现它。
参考文章: https://medium.com/javarevisited/how-to-filter-distinct-elements-in-java-477ed0e3d27b
推荐书单
1.《项目驱动零起点学Java》
购买链接:https://item.jd.com/13607758.html
《项目驱动零起点学Java》贯穿6个完整项目,经过作者多年教学经验提炼而得,项目从小到大、从短到长,可以让读者在练习项目的过程中,快速掌握一系列知识点。
作者是国内知名Java教学者和传播者,一路披荆斩棘,兢兢业业20余年。积累了丰富的“培”“训”经验,也产出了很多优质的教学理论。
Java语言经过数十年的发展,体系逐渐变得庞大而复杂,本书芟繁就简,提炼出了最为重要的知识点,可以让读者轻松上手。本书配套有专栏课程,课程中提供了扩展内容。
《项目驱动零起点学Java》共分 13 章,围绕 6 个项目和 258 个代码示例,分别介绍了走进Java 的世界、变量与数据类型、运算符、流程控制、方法、数组、面向对象、异常、常用类、集合、I/O流、多线程、网络编程相关内容。《项目驱动零起点学Java》总结了马士兵老师从事Java培训十余年来经受了市场检验的教研成果,通过6 个项目以及每章的示例和习题,可以帮助读者快速掌握Java 编程的语法以及算法实现。扫描每章提供的二维码可观看相应章节内容的视频讲解。
2.《Java编程讲义》
购买链接:https://item.jd.com/13495830.html
《Java编程讲义》根据目前Java开发领域的实际需求,从初学者角度出发,详细讲解了Java技术的基础知识。
全书共15章,包括Java开发入门,Java语言基础,Java控制结构,数组,面向对象编程,继承和多态,抽象类、接口和内部类,异常处理,Java常用类库,集合与泛型,Lambda表达式,输入-输出流,多线程,JDBC数据库技术,网络编程等内容。内容全面覆盖.1ava开发必备的基础知识点,结合生活化案例展开讲解,程序代码给出了详细的注释,能够使初学者轻松领会Java技术精髓,快速掌握Java开发技能。
《Java编程讲义》适合作为高等院校相关专业的教材及教学参考书,也适合作为Java开发入门者的自学用书,还可供开发人员查阅、参考。
精彩回顾
扫码关注《Java学研大本营》,加入读者群,分享更多精彩