Skip to main content

Command Palette

Search for a command to run...

Bài 4: Map Interface và Các Implementations

Published
9 min readView as Markdown

I. Giới Thiệu Về Map Interface

Map là một interface trong Java Collection Framework đại diện cho một tập hợp các cặp khóa-giá trị (key-value pairs). Mỗi khóa là duy nhất, và mỗi khóa chỉ liên kết với một giá trị. Map không là một phần của Collection interface, nhưng nó là một phần của Java Collections Framework. Map thường được sử dụng để lưu trữ và truy xuất dữ liệu dựa trên khóa.

II. Các Phương Thức Chính Trong Map Interface

  1. V put(K key, V value)

    • Thêm một cặp khóa-giá trị vào Map. Nếu khóa đã tồn tại, giá trị cũ sẽ được thay thế bởi giá trị mới.

    • Ví dụ:

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "A");
        map.put(2, "B");
        map.put(1, "C"); // Thay thế giá trị của khóa 1
        System.out.println(map); // Output: {1=C, 2=B}
      
  2. V get(Object key)

    • Trả về giá trị liên kết với khóa key. Nếu khóa không tồn tại, trả về null.

    • Ví dụ:

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "A");
        map.put(2, "B");
        String value = map.get(1);
        System.out.println(value); // Output: A
      
  3. V remove(Object key)

    • Xóa cặp khóa-giá trị khỏi Map dựa trên khóa key. Trả về giá trị liên kết với khóa nếu tồn tại, ngược lại trả về null.

    • Ví dụ:

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "A");
        map.put(2, "B");
        String removedValue = map.remove(1);
        System.out.println(removedValue); // Output: A
        System.out.println(map); // Output: {2=B}
      
  4. boolean containsKey(Object key)

    • Kiểm tra xem Map có chứa khóa key hay không. Trả về true nếu có, ngược lại trả về false.

    • Ví dụ:

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "A");
        boolean contains = map.containsKey(1);
        System.out.println(contains); // Output: true
      
  5. boolean containsValue(Object value)

    • Kiểm tra xem Map có chứa giá trị value hay không. Trả về true nếu có, ngược lại trả về false.

    • Ví dụ:

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "A");
        boolean contains = map.containsValue("A");
        System.out.println(contains); // Output: true
      
  6. Set keySet()

    • Trả về tập hợp các khóa trong Map.

    • Ví dụ:

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "A");
        map.put(2, "B");
        Set<Integer> keys = map.keySet();
        System.out.println(keys); // Output: [1, 2]
      
  7. Collection values()

    • Trả về tập hợp các giá trị trong Map.

    • Ví dụ:

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "A");
        map.put(2, "B");
        Collection<String> values = map.values();
        System.out.println(values); // Output: [A, B]
      
  8. Set<Map.Entry<K, V>> entrySet()

    • Trả về tập hợp các cặp khóa-giá trị trong Map.

    • Ví dụ:

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "A");
        map.put(2, "B");
        Set<Map.Entry<Integer, String>> entries = map.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
        // Output: 
        // 1 = A
        // 2 = B
      

III. Các Lớp Triển Khai Map Interface

  1. HashMap

    • Đặc điểm:

      • Dựa trên bảng băm (hash table).

      • Không duy trì thứ tự các phần tử.

      • Hiệu suất tốt cho các thao tác thêm, xóa, và tìm kiếm phần tử (O(1)).

    • Khi nào sử dụng: Khi cần một tập hợp không trùng lặp và không quan tâm đến thứ tự phần tử.

    • Ví dụ:

        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "A");
        hashMap.put(2, "B");
        hashMap.put(1, "C"); // Thay thế giá trị của khóa 1
        System.out.println(hashMap); // Output: {1=C, 2=B}
      
  2. LinkedHashMap

    • Đặc điểm:

      • Kế thừa từ HashMap và sử dụng danh sách liên kết kép để duy trì thứ tự chèn.

      • Hiệu suất tương tự như HashMap nhưng có thêm chi phí để duy trì thứ tự (O(1)).

    • Khi nào sử dụng: Khi cần một tập hợp không trùng lặp nhưng duy trì thứ tự chèn.

    • Ví dụ:

        Map<Integer, String> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put(1, "A");
        linkedHashMap.put(2, "B");
        linkedHashMap.put(1, "C"); // Thay thế giá trị của khóa 1
        System.out.println(linkedHashMap); // Output: {1=C, 2=B}
      
  3. TreeMap

    • Đặc điểm:

      • Dựa trên cây nhị phân tìm kiếm (Red-Black tree).

      • Duy trì thứ tự các phần tử theo thứ tự tự nhiên hoặc theo bộ so sánh (comparator) tùy chỉnh.

      • Hiệu suất cho các thao tác thêm, xóa, và tìm kiếm là O(log n).

    • Khi nào sử dụng: Khi cần một tập hợp không trùng lặp và duy trì thứ tự sắp xếp.

    • Ví dụ:

        Map<Integer, String> treeMap = new TreeMap<>();
        treeMap.put(2, "B");
        treeMap.put(1, "A");
        treeMap.put(3, "C");
        System.out.println(treeMap); // Output: {1=A, 2=B, 3=C}
      
  4. Hashtable

    • Đặc điểm:

      • Giống như HashMap nhưng có tính đồng bộ (synchronized).

      • Hiệu năng kém hơn HashMap do tính đồng bộ.

    • Khi nào sử dụng: Khi cần một Map hỗ trợ đa luồng (multi-threading).

    • Ví dụ:

        Map<Integer, String> hashtable = new Hashtable<>();
        hashtable.put(1, "A");
        hashtable.put(2, "B");
        hashtable.put(1, "C"); // Thay thế giá trị của khóa 1
        System.out.println(hashtable); // Output: {1=C, 2=B}
      
  5. ConcurrentHashMap

    • Đặc điểm:

      • Một phiên bản đồng bộ của HashMap được tối ưu hóa cho môi trường đa luồng.

      • Hỗ trợ đồng thời nhiều thao tác đọc và viết.

    • Khi nào sử dụng: Khi cần một Map đồng bộ và hiệu suất cao trong môi trường đa luồng.

    • Ví dụ:

        Map<Integer, String> concurrentHashMap = new ConcurrentHashMap<>();
        concurrentHashMap.put(1, "A");
        concurrentHashMap.put(2, "B");
        concurrentHashMap.put(1, "C"); // Thay thế giá trị của khóa 1
        System.out.println(concurrentHashMap); // Output: {1=C, 2=B}
      

IV. So Sánh Hiệu Năng Và Trường Hợp Sử Dụng

LớpThứ Tự Phần TửHiệu Suất Thêm/XóaHiệu Suất Tìm KiếmĐồng BộKhi Nào Sử Dụng
HashMapKhôngRất nhanh (O(1))Rất nhanh (O(1))KhôngKhi không cần thứ tự
LinkedHashMapTheo thứ tự chènNhanh (O(1))Nhanh (O(1))KhôngKhi cần duy trì thứ tự chèn
TreeMapTheo thứ tự sắp x

ếp | Trung bình (O(log n)) | Trung bình (O(log n)) | Không | Khi cần sắp xếp phần tử | | Hashtable | Không | Rất nhanh (O(1)) | Rất nhanh (O(1)) | Có | Khi cần hỗ trợ đa luồng | | ConcurrentHashMap | Không | Rất nhanh (O(1)) | Rất nhanh (O(1)) | Có | Khi cần đồng bộ và hiệu suất cao |

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

  1. Sử Dụng HashMap

    Mô tả: Lưu trữ thông tin sinh viên theo mã sinh viên.

     import java.util.HashMap;
     import java.util.Map;
    
     public class HashMapExample {
         public static void main(String[] args) {
             Map<Integer, String> studentMap = new HashMap<>();
             studentMap.put(1, "John Doe");
             studentMap.put(2, "Jane Smith");
             studentMap.put(3, "Mike Johnson");
    
             // Truy xuất thông tin sinh viên theo mã sinh viên
             String student = studentMap.get(2);
             System.out.println("Student with ID 2: " + student);
    
             // Kiểm tra xem có sinh viên với mã 4 không
             boolean hasStudent = studentMap.containsKey(4);
             System.out.println("Has student with ID 4: " + hasStudent);
         }
     }
    
  2. Sử Dụng LinkedHashMap

    Mô tả: Lưu trữ và duy trì thứ tự chèn các sản phẩm trong giỏ hàng.

     import java.util.LinkedHashMap;
     import java.util.Map;
    
     public class LinkedHashMapExample {
         public static void main(String[] args) {
             Map<String, Integer> cart = new LinkedHashMap<>();
             cart.put("Apple", 3);
             cart.put("Banana", 2);
             cart.put("Orange", 5);
    
             // In ra các sản phẩm trong giỏ hàng theo thứ tự chèn
             for (Map.Entry<String, Integer> entry : cart.entrySet()) {
                 System.out.println(entry.getKey() + ": " + entry.getValue());
             }
         }
     }
    
  3. Sử Dụng TreeMap

    Mô tả: Lưu trữ và sắp xếp các điểm số sinh viên theo thứ tự mã sinh viên.

     import java.util.Map;
     import java.util.TreeMap;
    
     public class TreeMapExample {
         public static void main(String[] args) {
             Map<Integer, Integer> scores = new TreeMap<>();
             scores.put(102, 85);
             scores.put(101, 90);
             scores.put(103, 75);
    
             // In ra các điểm số theo thứ tự mã sinh viên
             for (Map.Entry<Integer, Integer> entry : scores.entrySet()) {
                 System.out.println("Student ID " + entry.getKey() + ": " + entry.getValue());
             }
         }
     }
    
  4. Sử Dụng ConcurrentHashMap

    Mô tả: Lưu trữ và truy xuất thông tin nhân viên trong một ứng dụng đa luồng.

     import java.util.Map;
     import java.util.concurrent.ConcurrentHashMap;
    
     public class ConcurrentHashMapExample {
         public static void main(String[] args) {
             Map<Integer, String> employeeMap = new ConcurrentHashMap<>();
             employeeMap.put(1, "Alice Brown");
             employeeMap.put(2, "Bob White");
             employeeMap.put(3, "Charlie Green");
    
             // Truy xuất thông tin nhân viên theo mã nhân viên trong môi trường đa luồng
             Runnable task = () -> {
                 String employee = employeeMap.get(2);
                 System.out.println("Employee with ID 2: " + employee);
             };
    
             Thread thread1 = new Thread(task);
             Thread thread2 = new Thread(task);
    
             thread1.start();
             thread2.start();
         }
     }
    

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

  1. Tạo chương trình Java sử dụng HashMap để quản lý danh bạ điện thoại.

    • Yêu cầu: Thêm, xóa, và tìm kiếm thông tin liên lạc dựa trên số điện thoại.

    • Ví dụ:

        import java.util.HashMap;
        import java.util.Map;
      
        public class PhoneBook {
            public static void main(String[] args) {
                Map<String, String> phoneBook = new HashMap<>();
                phoneBook.put("123-456-7890", "John Doe");
                phoneBook.put("098-765-4321", "Jane Smith");
      
                // Thêm liên lạc mới
                phoneBook.put("111-222-3333", "Alice Brown");
      
                // Xóa liên lạc
                phoneBook.remove("098-765-4321");
      
                // Tìm kiếm liên lạc
                String contact = phoneBook.get("123-456-7890");
                System.out.println("Contact with phone number 123-456-7890: " + contact);
            }
        }
      
  2. Tạo chương trình Java sử dụng LinkedHashMap để quản lý lịch sử truy cập web.

    • Yêu cầu: Thêm URL mới vào lịch sử, in ra lịch sử truy cập theo thứ tự chèn.

    • Ví dụ:

        import java.util.LinkedHashMap;
        import java.util.Map;
      
        public class BrowserHistory {
            public static void main(String[] args) {
                Map<String, String> history = new LinkedHashMap<>();
                history.put("google.com", "Google");
                history.put("yahoo.com", "Yahoo");
                history.put("bing.com", "Bing");
      
                // Thêm URL mới vào lịch sử
                history.put("github.com", "GitHub");
      
                // In ra lịch sử truy cập theo thứ tự chèn
                for (Map.Entry<String, String> entry : history.entrySet()) {
                    System.out.println(entry.getKey() + ": " + entry.getValue());
                }
            }
        }
      
  3. Tạo chương trình Java sử dụng TreeMap để quản lý danh sách học sinh và điểm số của họ theo thứ tự tăng dần của mã học sinh.

    • Yêu cầu: Thêm, xóa và in ra danh sách học sinh theo thứ tự tăng dần của mã học sinh.

    • Ví dụ:

        import java.util.Map;
        import java.util.TreeMap;
      
        public class StudentScores {
            public static void main(String[] args) {
                Map<Integer, Integer> scores = new TreeMap<>();
                scores.put(103, 75);
                scores.put(101, 90);
                scores.put(102, 85);
      
                // Thêm điểm số học sinh mới
                scores.put(104, 80);
      
                // Xóa điểm số học sinh
                scores.remove(103);
      
                // In ra danh sách học sinh theo thứ tự tăng dần của mã học sinh
                for (Map.Entry<Integer, Integer> entry : scores.entrySet()) {
                    System.out.println("Student ID " + entry.getKey() + ": " + entry.getValue());
                }
            }
        }
      
  4. Tạo chương trình Java sử dụng ConcurrentHashMap để quản lý dữ liệu phiên truy cập người dùng trong một ứng dụng đa luồng.

    • Yêu cầu: Thêm, xóa và truy xuất thông tin phiên truy cập một cách an toàn trong môi trường đa luồng.

    • Ví dụ:

        import java.util.Map;
        import java.util.concurrent.ConcurrentHashMap;
      
        public class UserSessions {
            public static void main(String[] args) {
                Map<String, String> sessions = new ConcurrentHashMap<>();
                sessions.put("session1", "User1");
                sessions.put("session2", "User2");
      
                // Thêm phiên truy cập mới
                sessions.put("session3", "User3");
      
                // Xóa phiên truy cập
                sessions.remove("session1");
      
                // Truy xuất thông tin phiên truy cập
                Runnable task = () -> {
                    String user = sessions.get("session2");
                    System.out.println("User with session2: " + user);
                };
      
                Thread thread1 = new Thread(task);
                Thread thread2 = new Thread(task);
      
                thread1.start();
                thread2.start();
            }
        }
      

VII. Kết Luận

Trong bài viết này, chúng ta đã khám phá Map interface và các lớp triển khai của nó. Hiểu rõ sự khác nhau và đặc điểm của từng loại Map sẽ giúp bạn chọn lựa cấu trúc dữ liệu phù hợp cho các tình huống cụ thể trong ứng dụng của mình. 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ế.

VIII. Tài Liệu Tham Khảo

  • Java SE Documentation: Java Collections Framework

  • "Effective Java" by Joshua Bloch: Các nguyên tắc và best practices khi sử dụng Collection Framework.

More from this blog

devngu

169 posts