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

3069

Bài viết được sự cho phép của tác giả Giang Phan

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.

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).

  10 Java Web Framework tốt nhất
  10 lý do cho thấy tại sao bạn nên theo học ngôn ngữ lập trình Java

Đố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.gpcoder.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 listWithDuplicateElements = new ArrayList();
        listWithDuplicateElements.add("JAVA");
        listWithDuplicateElements.add("J2EE");
        listWithDuplicateElements.add("JSP");
        listWithDuplicateElements.add("SERVLETS");
        listWithDuplicateElements.add("JAVA");
        listWithDuplicateElements.add("STRUTS");
        listWithDuplicateElements.add("JSP");

        List listWithoutDuplicateElements = listWithDuplicateElements
                .stream()
                .distinct()
                .collect(Collectors.toList());
        System.out.println(listWithoutDuplicateElements); // [JAVA, J2EE, JSP, SERVLETS, STRUTS]
    }
}

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 HashSetLinkedHashSet để kiểm tra tồn tại và loại bỏ phần nó.

Ví dụ:

package com.gpcoder.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 listWithDuplicateElements = new ArrayList();
        listWithDuplicateElements.add("JAVA");
        listWithDuplicateElements.add("J2EE");
        listWithDuplicateElements.add("JSP");
        listWithDuplicateElements.add("SERVLETS");
        listWithDuplicateElements.add("JAVA");
        listWithDuplicateElements.add("STRUTS");
        listWithDuplicateElements.add("JSP");

        Set elementsAlreadySeen = new LinkedHashSet<>();
        listWithDuplicateElements.removeIf(s -> !elementsAlreadySeen.add(s));
        System.out.println(elementsAlreadySeen); // [JAVA, J2EE, JSP, SERVLETS, STRUTS]
    }
}

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 HashSetLinkedHashSet / 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.gpcoder.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 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 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.

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm Việc làm java hấp dẫn trên TopDev