Loại bỏ các phần tử trùng trong một ArrayList như thế nào trong Java 8?

Trong bài viết Loại bỏ các phần tử trùng trong một ArrayList , tôi đã giới thiệu với các bạn các cách để loại bỏ phần tử trùng trong một ArrayList với Java <= 7. Trong bài này, tôi sẽ giới thiệu với các bạn một số cách khác với sự hỗ trợ của các tính năng mới trong Java 8.

1. Sử dụng phương thức distinct() trong Stream API

Phương thức distinct() trả về một Stream gồm các phần tử duy nhất, việc xác định các phần tử trùng lặp được so sánh theo theo phương thức Object.equals(Object).

Đối với ordered Stream, thứ tự sắp xếp các phần tử là ổn định (stable) : đối với các phần tử trùng lặp, phần tử xuất hiện đầu tiên trong vùng gặp phải được giữ nguyên.

Đối với các unordered Stream, không đảm bảo tính ổn định (unstable) thứ tự các phần tử.

Ví dụ:

package com.maixuanviet.remove_duplicate;
 
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
 
public class RemoveDuplicateInArrayList1 {
 
    public static void main(String[] args) {
        List<String> listWithDuplicateElements = new ArrayList<String>();
        listWithDuplicateElements.add("JAVA");
        listWithDuplicateElements.add("J2EE");
        listWithDuplicateElements.add("JSP");
        listWithDuplicateElements.add("SERVLETS");
        listWithDuplicateElements.add("JAVA");
        listWithDuplicateElements.add("STRUTS");
        listWithDuplicateElements.add("JSP");
 
        List<String> listWithoutDuplicateElements = listWithDuplicateElements
                .stream()
                .distinct() 
                .collect(Collectors.toList());
        System.out.println(listWithoutDuplicateElements); // [JAVA, J2EE, JSP, SERVLETS, STRUTS]
    }
}

2. Sử dụng phương thức removeIf()

Phương thức removeIf() : chấp nhận đối số là 1 Predicate, nó loại bỏ tất cả các phần tử của Collection thỏa mãn điều kiện đã cho.

Ý tưởng cách này là lợi dụng tính năng không chứa phần tử trùng của HashSet/ LinkedHashSet để kiểm tra tồn tại và loại bỏ phần nó.

Ví dụ:

package com.maixuanviet.remove_duplicate;
 
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
 
public class RemoveDuplicateInArrayList2 {
 
    public static void main(String[] args) {
        List<String> listWithDuplicateElements = new ArrayList<String>();
        listWithDuplicateElements.add("JAVA");
        listWithDuplicateElements.add("J2EE");
        listWithDuplicateElements.add("JSP");
        listWithDuplicateElements.add("SERVLETS");
        listWithDuplicateElements.add("JAVA");
        listWithDuplicateElements.add("STRUTS");
        listWithDuplicateElements.add("JSP");
 
        Set<String> elementsAlreadySeen = new LinkedHashSet<>();
        listWithDuplicateElements.removeIf(s -> !elementsAlreadySeen.add(s));
        System.out.println(elementsAlreadySeen); // [JAVA, J2EE, JSP, SERVLETS, STRUTS]
    }
}

3. Sử dụng phương thức collect() với Collectors.toCollection

Phương thức collect() chấp nhận đối số là một Collector. Trong Java 8, chúng ta có thể sử dụng phương thức Collectors.toCollection() để tạo ra Collector. Phương thức này, chấp nhận đối số là Supplier. Ý tưởng cách này cũng là lợi dụng tính năng không chứa phần tử trùng của HashSet/ LinkedHashSet / TreeSet.

Ví dụ bên dưới dùng để loại bỏ các sinh viên có cùng email với TreeSet.

package com.maixuanviet.remove_duplicate;
 
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
 
class Student {
    private String name;
    private String email;
 
    public Student(String name, String email) {
        super();
        this.name = name;
        this.email = email;
    }
 
    public String getName() {
        return name;
    }
 
    public String getEmail() {
        return email;
    }
 
    @Override
    public String toString() {
        return "Student [name=" + name + ", email=" + email + "]";
    }
}
 
public class RemoveDuplicateInArrayList3 {
 
    public static void main(String[] args) {
        List<Student> studentsWithtDuplicate = new ArrayList<>();
        studentsWithtDuplicate.add(new Student("Nguyen Nhat", "nguyennhat@gmail.com"));
        studentsWithtDuplicate.add(new Student("Le Van", "levan@gmail.com"));
        studentsWithtDuplicate.add(new Student("Tran Khoa", "trankhoa@gmail.com"));
        studentsWithtDuplicate.add(new Student("Le Vo", "levan@gmail.com"));
        studentsWithtDuplicate.add(new Student("Ly Nguyen", "lynguyen@gmail.com"));
 
        Set<Student> studentsWithoutDuplicate = studentsWithtDuplicate.stream()
                .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Student::getEmail))));
        studentsWithoutDuplicate.forEach(s -> System.out.println(s));
    }
}

Output của chương trình:

Student [name=Le Van, email=levan@gmail.com]
Student [name=Ly Nguyen, email=lynguyen@gmail.com]
Student [name=Nguyen Nhat, email=nguyennhat@gmail.com]
Student [name=Tran Khoa, email=trankhoa@gmail.com]

Trong thực tế, người ta thường sử dụng phương thức distinct() để loại phần tử trùng. Sử dụng removeIf() hay collect() không tốt về performance so với distinct() và nó trả về một Set thay vì List như mong muốn, cần phải chuyển Set sang List. Tuy nhiên trong một số trường hợp chúng ta cũng có thể sử dụng cách này, nên tôi cũng giới thiệu với các bạn để thêm lựa chọn khi sử dụng.

Related posts:

So sánh HashMap và HashSet trong Java
Java Program to Find Transpose of a Graph Matrix
Check if there is mail waiting
String Initialization in Java
Spring Boot - Build Systems
Test a REST API with Java
Java Program to Implement the Alexander Bogomolny’s UnOrdered Permutation Algorithm for Elements Fro...
Giới thiệu SOAP UI và thực hiện test Web Service
Implementing a Runnable vs Extending a Thread
Converting between an Array and a List in Java
Biểu thức Lambda trong Java 8 – Lambda Expressions
Handling Errors in Spring WebFlux
Tổng quan về ngôn ngữ lập trình java
@Order in Spring
Spring WebClient and OAuth2 Support
Spring Boot with Multiple SQL Import Files
Làm thế nào tạo instance của một class mà không gọi từ khóa new?
How to Remove the Last Character of a String?
Java Program to implement Sparse Vector
Java Program to Check if a Point d lies Inside or Outside a Circle Defined by Points a, b, c in a Pl...
Show Hibernate/JPA SQL Statements from Spring Boot
Java Program to Perform Insertion in a 2 Dimension K-D Tree
Đồng bộ hóa các luồng trong Java
Hướng dẫn Java Design Pattern – Object Pool
Custom Cascading in Spring Data MongoDB
Ignore Null Fields with Jackson
Checked and Unchecked Exceptions in Java
Hướng dẫn Java Design Pattern – Flyweight
HashSet trong Java hoạt động như thế nào?
Java Program to Implement Warshall Algorithm
OAuth2 for a Spring REST API – Handle the Refresh Token in AngularJS
Java Program to Perform Stooge Sort