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:

Java Program to Find a Good Feedback Edge Set in a Graph
Guide to Java OutputStream
Java Program to Implement the Edmond’s Algorithm for Maximum Cardinality Matching
Java Program to Implement Self Balancing Binary Search Tree
Generic Constructors in Java
Java Program to Permute All Letters of an Input String
Instance Profile Credentials using Spring Cloud
Request a Delivery / Read Receipt in Javamail
Getting Started with Custom Deserialization in Jackson
Java Program to Apply Above-Below-on Test to Find the Position of a Point with respect to a Line
Java Program to Implement Word Wrap Problem
Java Program to Check whether Undirected Graph is Connected using BFS
Java Program to Check if a Directed Graph is a Tree or Not Using DFS
Java NIO2 Path API
4 tính chất của lập trình hướng đối tượng trong Java
Java Program to Find a Good Feedback Vertex Set
Chương trình Java đầu tiên
Intro to Spring Boot Starters
Form Validation with AngularJS and Spring MVC
Java Program for Douglas-Peucker Algorithm Implementation
Java Program to Implement Hash Tables with Quadratic Probing
Rest Web service: Filter và Interceptor với Jersey 2.x (P1)
Java Program to Implement Counting Sort
Inheritance and Composition (Is-a vs Has-a relationship) in Java
Tránh lỗi NullPointerException trong Java như thế nào?
The HttpMediaTypeNotAcceptableException in Spring MVC
Lập trình mạng với java
Java Program to Compute Cross Product of Two Vectors
Apache Commons Collections BidiMap
Java Program to Compute Discrete Fourier Transform Using Naive Approach
A Guide to Apache Commons Collections CollectionUtils
Check If a File or Directory Exists in Java