# Bài 9: Best Practices và Performance Tuning

#### I. Giới Thiệu

Sử dụng các Collection Framework một cách hiệu quả không chỉ giúp cải thiện hiệu suất của ứng dụng mà còn giúp mã nguồn dễ đọc, dễ bảo trì hơn. Bài viết này sẽ hướng dẫn các best practices và cách tối ưu hóa hiệu suất khi làm việc với Collection Framework trong Java.

#### II. Best Practices Khi Sử Dụng Collection

1. **Chọn Collection Phù Hợp**
    
    Việc chọn đúng loại collection là rất quan trọng để đảm bảo hiệu suất và tính đúng đắn của ứng dụng. Dưới đây là một số hướng dẫn cơ bản:
    
    * **ArrayList vs. LinkedList:** Sử dụng `ArrayList` khi cần truy cập ngẫu nhiên nhanh. Sử dụng `LinkedList` khi cần thêm/xóa phần tử thường xuyên ở đầu hoặc giữa danh sách.
        
    * **HashMap vs. TreeMap:** Sử dụng `HashMap` khi không cần thứ tự các phần tử. Sử dụng `TreeMap` khi cần duy trì thứ tự sắp xếp.
        
    * **HashSet vs. TreeSet:** Sử dụng `HashSet` khi không cần thứ tự các phần tử. Sử dụng `TreeSet` khi cần duy trì thứ tự sắp xếp.
        
2. **Khởi Tạo Kích Thước Ban Đầu**
    
    Khởi tạo kích thước ban đầu phù hợp cho các collection như `ArrayList` và `HashMap` có thể giúp giảm số lần mở rộng và cải thiện hiệu suất.
    
    ```java
    List<String> list = new ArrayList<>(100); // Khởi tạo với kích thước ban đầu 100
    Map<String, Integer> map = new HashMap<>(50); // Khởi tạo với kích thước ban đầu 50
    ```
    
3. **Sử Dụng Generics**
    
    Sử dụng generics để đảm bảo type-safety và tránh lỗi thời gian chạy.
    
    ```java
    List<String> list = new ArrayList<>(); // Đảm bảo chỉ thêm chuỗi vào danh sách
    list.add("Hello");
    // list.add(123); // Lỗi biên dịch
    ```
    
4. **Sử Dụng Interface Thay Vì Implementation**
    
    Sử dụng interface thay vì lớp triển khai để tăng tính linh hoạt và dễ bảo trì.
    
    ```java
    List<String> list = new ArrayList<>(); // Khuyến nghị
    ArrayList<String> list = new ArrayList<>(); // Không khuyến nghị
    ```
    
5. **Tránh Sử Dụng Synchronized Collection**
    
    Tránh sử dụng các collection đồng bộ hóa (`Collections.synchronizedList`, `Collections.synchronizedMap`) khi không cần thiết. Thay vào đó, sử dụng các concurrent collections như `ConcurrentHashMap`.
    
    ```java
    Map<String, Integer> map = new ConcurrentHashMap<>();
    ```
    

#### III. Performance Tuning

1. **Sử Dụng Primitive Types Khi Có Thể**
    
    Sử dụng các kiểu nguyên thủy (`int`, `long`,...) thay vì các kiểu đối tượng (`Integer`, `Long`,...) để tránh boxing/unboxing và cải thiện hiệu suất.
    
    ```java
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < 1000; i++) {
        list.add(i); // Boxing mỗi lần thêm phần tử
    }
    ```
    
2. **Sử Dụng For-Each Thay Vì Iterator**
    
    Sử dụng vòng lặp for-each thay vì iterator để làm mã nguồn ngắn gọn và dễ hiểu hơn.
    
    ```java
    List<String> list = Arrays.asList("A", "B", "C");
    for (String item : list) {
        System.out.println(item);
    }
    ```
    
3. **Tránh Sử Dụng Collection.addAll() Khi Có Thể**
    
    Tránh sử dụng `Collection.addAll()` với một lượng lớn phần tử. Thay vào đó, khởi tạo collection mới với các phần tử cần thiết.
    
    ```java
    List<String> list1 = Arrays.asList("A", "B", "C");
    List<String> list2 = new ArrayList<>(list1); // Tốt hơn là sử dụng addAll()
    ```
    
4. **Sử Dụng Stream API**
    
    Stream API cung cấp các phương thức hiệu quả để thao tác trên các collection một cách dễ dàng và tối ưu.
    
    ```java
    List<String> list = Arrays.asList("a", "b", "c");
    List<String> upperList = list.stream()
        .map(String::toUpperCase)
        .collect(Collectors.toList());
    ```
    

#### IV. Ví Dụ Minh Họa Chi Tiết

1. **Chọn Collection Phù Hợp**
    
    **Mô tả:** Sử dụng `ArrayList` để lưu trữ danh sách sản phẩm và `HashMap` để lưu trữ thông tin số lượng sản phẩm theo mã sản phẩm.
    
    ```java
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class ProductInventory {
        private List<String> products = new ArrayList<>();
        private Map<String, Integer> productQuantities = new HashMap<>();
    
        public void addProduct(String product, int quantity) {
            products.add(product);
            productQuantities.put(product, quantity);
        }
    
        public int getProductQuantity(String product) {
            return productQuantities.getOrDefault(product, 0);
        }
    
        public static void main(String[] args) {
            ProductInventory inventory = new ProductInventory();
            inventory.addProduct("Laptop", 50);
            inventory.addProduct("Smartphone", 100);
    
            System.out.println("Laptop quantity: " + inventory.getProductQuantity("Laptop")); // Output: Laptop quantity: 50
            System.out.println("Smartphone quantity: " + inventory.getProductQuantity("Smartphone")); // Output: Smartphone quantity: 100
        }
    }
    ```
    
2. **Khởi Tạo Kích Thước Ban Đầu**
    
    **Mô tả:** Tạo `ArrayList` và `HashMap` với kích thước ban đầu phù hợp.
    
    ```java
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class InitialCapacityExample {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>(100); // Khởi tạo với kích thước ban đầu 100
            Map<String, Integer> map = new HashMap<>(50); // Khởi tạo với kích thước ban đầu 50
    
            list.add("A");
            map.put("Apple", 1);
    
            System.out.println("List: " + list); // Output: List: [A]
            System.out.println("Map: " + map); // Output: Map: {Apple=1}
        }
    }
    ```
    
3. **Sử Dụng Generics**
    
    **Mô tả:** Sử dụng generics để đảm bảo type-safety.
    
    ```java
    import java.util.ArrayList;
    import java.util.List;
    
    public class GenericsExample {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>(); // Đảm bảo chỉ thêm chuỗi vào danh sách
            list.add("Hello");
            // list.add(123); // Lỗi biên dịch
    
            System.out.println(list); // Output: [Hello]
        }
    }
    ```
    
4. **Sử Dụng Stream API**
    
    **Mô tả:** Sử dụng Stream API để lọc và ánh xạ các phần tử trong danh sách.
    
    ```java
    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;
    
    public class StreamAPIExample {
        public static void main(String[] args) {
            List<String> list = Arrays.asList("apple", "banana", "cherry");
    
            List<String> upperList = list.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
    
            System.out.println("Upper List: " + upperList); // Output: [APPLE, BANANA, CHERRY]
        }
    }
    ```
    

#### V. Bài Tập Thực Hành

1. **Tạo chương trình Java sử dụng ArrayList để lưu trữ danh sách sinh viên và HashMap để lưu trữ điểm của sinh viên.**
    
    * Yêu cầu: Sử dụng ArrayList để lưu trữ tên sinh viên và HashMap để lưu trữ điểm của sinh viên theo tên.
        
    * Ví dụ:
        
        ```java
        import java.util.ArrayList;
        import java.util.HashMap;
        import java.util.List;
        import java.util.Map;
        
        public class StudentScores {
            private List<String> students = new ArrayList<>();
            private Map<String, Integer> scores = new HashMap<>();
        
            public void addStudent(String student, int score) {
                students.add(student);
                scores.put(student, score);
            }
        
            public int getScore(String student) {
                return scores.getOrDefault(student, 0);
            }
        
            public static void main(String[] args) {
                StudentScores studentScores = new StudentScores();
                studentScores.addStudent("Alice", 90);
                studentScores.addStudent("Bob", 85);
        
                System.out.println("Alice's score: " + studentScores.getScore("Alice")); // Output: Alice's score: 90
                System.out.println("Bob's score: " + studentScores.get
        ```
        

Score("Bob")); // Output: Bob's score: 85 } } \`\`\`

2. **Tạo chương trình Java sử dụng ConcurrentHashMap để quản lý số lượng sản phẩm trong kho.**
    
    * Yêu cầu: Sử dụng ConcurrentHashMap để đảm bảo tính đồng bộ khi thêm và lấy thông tin sản phẩm.
        
    * Ví dụ:
        
        ```java
        import java.util.concurrent.ConcurrentHashMap;
        import java.util.Map;
        
        public class Warehouse {
            private final Map<String, Integer> stock = new ConcurrentHashMap<>();
        
            public void addProduct(String product, int quantity) {
                stock.merge(product, quantity, Integer::sum);
            }
        
            public int getProductQuantity(String product) {
                return stock.getOrDefault(product, 0);
            }
        
            public static void main(String[] args) {
                Warehouse warehouse = new Warehouse();
                warehouse.addProduct("Laptop", 10);
                warehouse.addProduct("Smartphone", 5);
        
                System.out.println("Laptop quantity: " + warehouse.getProductQuantity("Laptop")); // Output: Laptop quantity: 10
                System.out.println("Smartphone quantity: " + warehouse.getProductQuantity("Smartphone")); // Output: Smartphone quantity: 5
            }
        }
        ```
        
3. **Tạo chương trình Java sử dụng Stream API để lọc danh sách các sản phẩm và ánh xạ để lấy tên sản phẩm.**
    
    * Yêu cầu: Lọc danh sách các sản phẩm có giá lớn hơn 100 và ánh xạ để lấy tên sản phẩm.
        
    * Ví dụ:
        
        ```java
        import java.util.Arrays;
        import java.util.List;
        import java.util.stream.Collectors;
        
        class Product {
            String name;
            double price;
        
            Product(String name, double price) {
                this.name = name;
                this.price = price;
            }
        
            public String getName() {
                return name;
            }
        
            public double getPrice() {
                return price;
            }
        }
        
        public class StreamFilterExample {
            public static void main(String[] args) {
                List<Product> products = Arrays.asList(
                    new Product("Laptop", 1200),
                    new Product("Smartphone", 800),
                    new Product("Tablet", 200),
                    new Product("Mouse", 50)
                );
        
                List<String> expensiveProductNames = products.stream()
                    .filter(product -> product.getPrice() > 100)
                    .map(Product::getName)
                    .collect(Collectors.toList());
        
                System.out.println("Expensive Products: " + expensiveProductNames); // Output: [Laptop, Smartphone, Tablet]
            }
        }
        ```
        
4. **Tạo chương trình Java sử dụng ArrayList để lưu trữ danh sách các số và tính tổng các số chẵn trong danh sách.**
    
    * Yêu cầu: Sử dụng ArrayList để lưu trữ các số và tính tổng các số chẵn trong danh sách.
        
    * Ví dụ:
        
        ```java
        import java.util.ArrayList;
        import java.util.List;
        
        public class EvenNumberSum {
            public static void main(String[] args) {
                List<Integer> numbers = new ArrayList<>();
                numbers.add(1);
                numbers.add(2);
                numbers.add(3);
                numbers.add(4);
                numbers.add(5);
        
                int sum = 0;
                for (int number : numbers) {
                    if (number % 2 == 0) {
                        sum += number;
                    }
                }
        
                System.out.println("Sum of even numbers: " + sum); // Output: Sum of even numbers: 6
            }
        }
        ```
        

#### VI. Kết Luận

Trong bài viết này, chúng ta đã khám phá các best practices và cách tối ưu hóa hiệu suất khi làm việc với Collection Framework trong Java. Hiểu rõ và áp dụng các best practices này sẽ giúp bạn xây dựng các ứng dụng hiệu quả và dễ bảo trì hơn. Các ví dụ minh họa và bài tập thực hành sẽ giúp củng cố kiến thức và ứng dụng hiệu quả trong các dự án thực tế.

#### VII. Tài Liệu Tham Khảo

* Java SE Documentation: [Java Collections Framework](https://docs.oracle.com/javase/8/docs/technotes/guides/collections/index.html)
    
* "Effective Java" by Joshua Bloch: Các nguyên tắc và best practices khi sử dụng Collection Framework.
