CodeGym /Các khóa học /JAVA 25 SELF /Chuyển đổi collection

Chuyển đổi collection

JAVA 25 SELF
Mức độ , Bài học
Có sẵn

1. Chuyển đổi phần tử của collection

Trong lập trình, một trong những thao tác thường gặp nhất — chuyển đổi collection: ta có một collection dữ liệu của một kiểu, và dựa trên đó cần tạo một collection mới của kiểu khác. Ví dụ, từ danh sách object kiểu User lấy danh sách tên của họ (String), hoặc từ danh sách số — danh sách bình phương của chúng.

Cách cơ bản và dễ hiểu nhất trong Java là sử dụng cách tiếp cận mệnh lệnh, tức là vòng lặp for thông thường (thường là for-each).

Ví dụ: từ danh sách chuỗi lấy danh sách độ dài của chúng

Giả sử ta có danh sách tên các thành phố:

List<String> cities = List.of("London", "Parizh", "Tokio", "Nyu-York");

Nhiệm vụ của ta là tạo danh sách mới chứa độ dài của từng tên. Kết quả cuối cùng cần là: [6, 6, 5, 8].

Giải pháp dùng vòng lặp for:

import java.util.ArrayList;
import java.util.List;

public class CollectionTransform {
    public static void main(String[] args) {
        List<String> cities = List.of("London", "Parizh", "Tokio", "Nyu-York");
        List<Integer> lengths = new ArrayList<>(); // Tạo một danh sách mới, rỗng để chứa kết quả

        for (String city : cities) {
            // Với mỗi phần tử trong cities, ta tính độ dài của nó...
            int length = city.length();
            // ...và thêm kết quả này vào danh sách mới
            lengths.add(length);
        }

        System.out.println(lengths); // Sẽ in: [6, 6, 5, 8]
    }
}

Ta bắt đầu bằng cách tạo một collection mới, rỗng để chứa kết quả — chuyển đổi không làm thay đổi collection gốc. Để duyệt qua collection gốc, dùng vòng lặp for-each và bên trong áp dụng logic cần thiết (length()) cho từng phần tử, rồi thêm kết quả vào danh sách mới qua add.

2. Chuyển đổi object

Ta thường làm việc với kiểu dữ liệu phức tạp hơn. Giả sử có lớp Product, và cần lấy danh sách tên (hoặc giá) của nó.

public class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

Bây giờ, với danh sách sản phẩm, ta lấy danh sách tên của chúng:

import java.util.ArrayList;
import java.util.List;

public class ProductExample {
    public static void main(String[] args) {
        List<Product> products = List.of(
            new Product("Laptop", 1200.0),
            new Product("Chuột", 25.5),
            new Product("Bàn phím", 75.0)
        );

        // Tạo danh sách mới cho tên sản phẩm
        List<String> productNames = new ArrayList<>();

        for (Product product : products) {
            // Với mỗi object Product, lấy tên của nó
            productNames.add(product.getName());
        }

        System.out.println(productNames); // Sẽ in: [Laptop, Chuột, Bàn phím]
    }
}

Logic vẫn vậy: lặp qua collection gốc, áp dụng phương thức cần thiết cho từng phần tử (ví dụ, getName()) và thêm kết quả vào collection mới.

3. Làm việc với collection lồng nhau

Xét trường hợp danh sách các danh sách: vài phòng ban, mỗi phòng có danh sách nhân viên riêng. Nhiệm vụ — lấy một danh sách chung (“phẳng”) chứa tất cả nhân viên.

Ví dụ: hợp nhất danh sách nhân viên

List<List<String>> departments = List.of(
    List.of("Anna", "Boris"),
    List.of("Viktoriya", "Gleb", "Dmitry"),
    List.of("Elena")
);

Ta muốn nhận được một danh sách duy nhất: [Anna, Boris, Viktoriya, Gleb, Dmitry, Elena].

Cách 1: dùng phương thức addAll()

import java.util.ArrayList;
import java.util.List;

public class NestedCollectionExample {
    public static void main(String[] args) {
        List<List<String>> departments = List.of(
            List.of("Anna", "Boris"),
            List.of("Viktoriya", "Gleb", "Dmitry"),
            List.of("Elena")
        );

        List<String> allEmployees = new ArrayList<>();

        // Duyệt qua từng danh sách (phòng ban)
        for (List<String> department : departments) {
            // Thêm tất cả phần tử của danh sách hiện tại vào danh sách chung
            allEmployees.addAll(department);
        }

        System.out.println(allEmployees); // [Anna, Boris, Viktoriya, Gleb, Dmitry, Elena]
    }
}

Cách 2: vòng lặp lồng nhau — tương tự nhưng làm “thủ công”:

List<List<String>> departments = List.of(...);
List<String> allEmployees = new ArrayList<>();

for (List<String> department : departments) { // Vòng lặp ngoài theo phòng ban
    for (String employee : department) {      // Vòng lặp trong theo nhân viên
        allEmployees.add(employee);
    }
}

System.out.println(allEmployees);

Cả hai cách đều cho kết quả như nhau. Phương thức addAll() thực chất đóng gói logic của vòng lặp lồng nhau và làm mã ngắn gọn hơn.

4. Trường hợp phức tạp và chuyển đổi có điều kiện

Đôi khi chỉ cần chuyển đổi cho các phần tử thỏa điều kiện. Ví dụ, lấy danh sách tên thành phố bắt đầu bằng chữ "N", rồi lấy độ dài của chúng. Ở đây ta kết hợp lọc và chuyển đổi: if + gọi phương thức (length()).

import java.util.ArrayList;
import java.util.List;

public class ConditionalTransform {
    public static void main(String[] args) {
        List<String> cities = List.of("London", "Parizh", "Tokio", "Nyu-York", "Nurnberg");
        List<Integer> lengths = new ArrayList<>();

        for (String city : cities) {
            // Trước hết kiểm tra điều kiện
            if (city.startsWith("N")) {
                // Nếu điều kiện đúng, tiến hành chuyển đổi
                lengths.add(city.length());
            }
        }

        System.out.println(lengths); // Sẽ in: [8, 8]
    }
}

Mẫu như sau: bên trong vòng lặp, đầu tiên lọc phần tử qua điều kiện (startsWith, so sánh, kiểm tra khoảng, v.v.), sau đó áp dụng chuyển đổi cần thiết và cho kết quả vào danh sách mới.

5. Lỗi thường gặp và cạm bẫy

Lỗi số 1: sửa đổi collection gốc trong khi duyệt. Lỗi phổ biến — cố gắng thêm/xóa phần tử khỏi collection gốc ngay trong vòng lặp for-each. Điều này dẫn đến lỗi và hành vi khó lường. Cách xử lý: luôn tạo danh sách mới cho kết quả và chỉ thêm vào đó.

Lỗi số 2: ép kiểu không đúng. Nếu bạn làm việc với collection “thô” (ví dụ, qua Object) và ép phần tử sang kiểu không đúng, bạn sẽ nhận ClassCastException. Hãy dùng generics (List<T>) và chú ý đến chữ ký (signature).

Lỗi số 3: sử dụng tài nguyên kém hiệu quả. Với collection rất lớn, việc liên tục tạo danh sách mới và sao chép phần tử có thể tốn bộ nhớ và thời gian đáng kể. Trong hầu hết bài toán hằng ngày điều này chấp nhận được, nhưng khi xử lý dữ liệu lớn hãy tính đến độ phức tạp và, nếu cần, tối ưu cách tiếp cận.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION