仅过滤 Collection 中的唯一元素
介绍
- 当我们从一台机器到另一台机器交换数据时,重复条目是非常常见的问题。
- 作为客户端,在使用这些记录时,我们必须实现一个逻辑来处理这些重复记录。
- 在本博客中,我们将了解如何在 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 来实现它。