Post

Map

1. Giới thiệu

Map là một tập dữ liệu được lưu dưới dạng key-value. Một Map không thể chứa những key trùng nhau, nhưng mỗi key thì có thể được ánh xạ đến nhiều hơn một giá trị.

Map interface được định nghĩa gồm những method phục vụ những hoạt động cơ bản (như put, get, remove, containsKey, containsValue, size, empty), phục vụ việc thao tác hàng loạt (như putAll, clear), và phục vụ việc xem dữ liệu trong tập (như keySet, entrySet, values).Map được sử dụng trong trường hợp chúng ta muốn truy xuất, cập nhật hoặc tìm kiếm phần tử thông qua khóa của phần tử đó.

Ví dụ thực tế mà chúng ta từng thấy như:

  • Một Map bao gồm thông tin của người quản lý và nhân viên trong một công ty. Mỗi một người quản lý (key) sẽ liên kết với danh sách các nhân viên mà người đó quản lý (value).
  • Một Map bao gồm thông tin của một lớp học và các sinh viên có trong lớp đó. Mỗi một lớp (key) sẽ liên kết với danh sách các sinh viên của lớp đó (value).

Code demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.*;

public class MapExample {
	public static void main(String args[]) {
		Map<String, Integer> hashMap = new HashMap<String, Integer>();

		hashMap.put("a", new Integer(100));
		hashMap.put("b", new Integer(200));
		hashMap.put("c", new Integer(300));
		hashMap.put("d", new Integer(400));

		// Duyệt qua Map
		for (Map.Entry<String, Integer> me : hashMap.entrySet()) {
			System.out.print(me.getKey() + ":");
			System.out.println(me.getValue());
		}
	}
}

2. Thao tác với Map-Interface và HashMap

Do Map là một Interface nên nó chỉ có thể được sử dụng với một lớp triển khai Interface này. Bây giờ, chúng ta hãy xem một vài trường hợp sử dụng với Hashmap nhe.

Adding Elements: Để thêm một phần tử vào map, chúng ta có thể sử dụng phương thức put(). Tuy nhiên, thứ tự chèn không được giữ lại trong map băm. Đối với mỗi phần tử, một hàm băm riêng biệt được tạo và các phần tử được lập chỉ mục dựa trên hàm băm này để làm cho nó hiệu quả hơn.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.*;

public class MapPut {
	public static void main(String args[]) {
		
		// Khởi tạo một Map mặc định
		Map<Integer, String> hm1 = new HashMap<>();

		// Khởi tạo Map sử dụng Generics
		Map<Integer, String> hm2 = new HashMap<Integer, String>();

		// Chèn các phần tử vào Map
		hm1.put(1, "Độc lập");
		hm1.put(2, "Tự do");
		hm1.put(3, "Hạnh phúc");

		hm2.put(new Integer(1), "Độc lập");
		hm2.put(new Integer(2), "Tự do");
		hm2.put(new Integer(3), "Hạnh phúc");

		System.out.println(hm1);
		System.out.println(hm2);
	}
}

Changing Elements: Sau khi thêm phần tử nếu chúng ta muốn thay đổi phần tử, có thể thực hiện bằng cách thêm lại phần tử bằng phương thức put(). Vì các phần tử trong map được lập chỉ mục bằng cách sử dụng các khóa, nên giá trị của khóa có thể được thay đổi bằng cách chỉ cần chèn giá trị cập nhật cho khóa mà chúng tôi muốn thay đổi.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.*;

public class MapPut {
	public static void main(String args[]) {
		
		// Khởi tạo một Map mặc định
		Map<Integer, String> hm1 = new HashMap<>();

		// Khởi tạo Map sử dụng Generics
		Map<Integer, String> hm2 = new HashMap<Integer, String>();

		// Chèn các phần tử vào Map
		hm1.put(1, "Độc lập");
		hm1.put(2, "Tự do");
		hm1.put(3, "Hạnh phúc");
		
		System.out.println(hm1);
		hm1.put(1, "Hùng mạnh");

		hm2.put(new Integer(1), "Độc lập");
		hm2.put(new Integer(2), "Tự do");
		hm2.put(new Integer(3), "Hạnh phúc");
		
		System.out.println(hm2);
		hm2.put(new Integer(3), "Trường thịnh");
		

		System.out.println(hm1);
		System.out.println(hm2);
	}
}

Removing Element: Để xóa một phần tử khỏi Map, chúng ta có thể sử dụng phương thức remove(). Phương thức này nhận giá trị khóa và xóa ánh xạ cho một khóa khỏi Map nếu nó có trong Map đó.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.*;

public class MapRemove {
	public static void main(String args[]) {

		// Khởi tạo Map sử dụng Generics
		Map<Integer, String> hm1 = new HashMap<Integer, String>();

		//  Chèn các phần tử vào Map
		hm1.put(new Integer(1), "Việt Nam");
		hm1.put(new Integer(2), "Cuba");
		hm1.put(new Integer(3), "Liên Xô");
		hm1.put(new Integer(4), "Trung Quốc");

		// Map  ban đầu
		System.out.println(hm1);

		hm1.remove(new Integer(4));

		// Map sau khi Removed
		System.out.println(hm1);
	}
}

Iterating Map: Có nhiều cách để lặp lại Map. Cách nổi tiếng nhất là sử dụng vòng lặp for-each và lấy các khóa. Giá trị của khóa được tìm thấy bằng cách sử dụng phương thức getValue().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.*;

public class MapIterating {
	public static void main(String args[]) {

		// Khởi tạo Map sử dụng Generics
		Map<Integer, String> hm1 = new HashMap<Integer, String>();

		// Chèn phần tử
		hm1.put(new Integer(1), "Độc lập");
		hm1.put(new Integer(2), "Tự do");
		hm1.put(new Integer(3), "Hạnh phúc");

		for (Map.Entry mapElement : hm1.entrySet()) {
			int key = (int) mapElement.getKey();

			// Tìm giá trị
			String value = (String) mapElement.getValue();

			System.out.println(key + " : " + value);
		}
	}
}

Đặc điểm của Map Interface:

  • Map không được chứa các khóa trùng lặp và mỗi khóa có thể ánh xạ đến nhiều nhất một giá trị. Khoá và giá trị có thể null trong HashMap và LinkedHashMap, nhưng TreeMap thì không.
  • Thứ tự của một map phụ thuộc vào các triển khai cụ thể. Ví dụ: TreeMap và LinkedHashMap có thứ tự có thể dự đoán được, trong khi HashMap thì không.
  • Có hai Interface để triển khai Map trong java. Đó là, Map và SortedMap, cùng với ba lớp: HashMap, TreeMap và LinkedHashMap.

3. Khi nào nên dùng Map và tại sao?

Map hoàn hảo để sử dụng cho việc lập map liên kết khóa-giá trị chẳng hạn như từ điển. Map được sử dụng để thực hiện tra cứu theo khóa hoặc khi ai đó muốn truy xuất và cập nhật các yếu tố bằng khóa. Một số ví dụ:

  • Map các mã lỗi và mô tả của chúng.
  • Map mã zip và thành phố.
  • Một map của các nhà quản lý và nhân viên. Mỗi người quản lý (khóa) được liên kết với một danh sách (giá trị) nhân viên mà anh ta quản lý.
  • Map các lớp học và học sinh. Mỗi lớp (khóa) được liên kết với một danh sách các sinh viên (giá trị).

Tạo đối tượng Map

Vì Map là một Interface nên chúng ta luôn cần một lớp để mở rộng Map và từ đó tạo ra đối tượng. Một Map được gọi là “an toàn” có thể được định nghĩa như sau:

1
2
// mục tiêu là kiểu của đối tượng được lưu trong Map
Map hm = new HashMap ();

4. Các lớp triển khai Map Interface

HashMap: là một phần trong collection của Java. Nó lưu trữ dữ liệu trong các cặp (Khóa, Giá trị). Để truy cập một giá trị, người ta phải biết khóa của nó. Lớp này sử dụng một kỹ thuật gọi là Hashing. Hashing là một kỹ thuật chuyển đổi một large-String thành small-String đại diện cho cùng một String. Giá trị ngắn hơn giúp lập chỉ mục và tìm kiếm nhanh hơn. Hãy xem cách tạo một đối tượng Map bằng cách sử dụng lớp này.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.*;

public class HashMapDemo {
	public static void main(String[] args) {
		Map<String, Integer> map = new HashMap<>();

		map.put("Michael", 10);
		map.put("Corleone", 30);
		map.put("Don", 20);

		for (Map.Entry<String, Integer> e : map.entrySet())
			System.out.println(e.getKey() + " " + e.getValue());
	}
}

LinkedHashMap: cũng giống như HashMap với một tính năng bổ sung là duy trì thứ tự các phần tử được chèn vào nó. HashMap cung cấp lợi thế là chèn, tìm kiếm và xóa nhanh chóng nhưng nó không bao giờ nhớ vị trí và thứ tự chèn mà LinkedHashMap cung cấp nơi các phần tử có thể được truy cập theo thứ tự chèn của chúng. Hãy xem cách tạo một đối tượng map bằng cách sử dụng lớp này.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.*;

public class LinkedHashMapDemo {
	public static void main(String[] args) {
		Map<String, Integer> map = new LinkedHashMap<>();

		map.put("Michael", 10);
		map.put("Corleone", 30);
		map.put("Don", 20);

		for (Map.Entry<String, Integer> e : map.entrySet())
			System.out.println(e.getKey() + " " + e.getValue());
	}
}

TreeMap: được sử dụng để triển khai Map interface và NavigableMap cùng với lớp Abstract. Map được sắp xếp theo thứ tự tự nhiên của các khóa của nó hoặc bởi một Comparator được cung cấp tại thời điểm tạo map, tùy thuộc vào phương thức khởi tạo nào được sử dụng. Điều này chứng tỏ đây là một cách hiệu quả để sắp xếp và lưu trữ các cặp khóa-giá trị. Thứ tự lưu trữ được duy trì bởi sơ đồ dạng cây phải nhất quán với bất kỳ sorted-map nào khác. Hãy xem cách tạo một đối tượng map bằng cách sử dụng lớp này.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.*;

public class TreeMapDemo {
	public static void main(String[] args) {
		Map<String, Integer> map = new TreeMap<>();

		map.put("Michael", 10);
		map.put("Corleone", 30);
		map.put("Don", 20);

		for (Map.Entry<String, Integer> e : map.entrySet())
			System.out.println(e.getKey() + " " + e.getValue());
	}
}

Map là một khái niệm khá mới đối với các bạn học lập trình bấy lâu nay. Nhưng với Java, Map là món ăn tinh thần không thể thiếu của các lập trình viên, điều này đòi hỏi bạn phải trang bị cho mình kiến thức tối thiểu về Map. Và nội dung của bài viết này đã làm được hơn sự mong đợi đó – việc thực hành còn lại là ở các bạn.

Bài viết mang tính chất “ghi chú, lưu trữ, chia sẻ và phi lợi nhuận”.
Nếu bạn thấy hữu ích, đừng quên chia sẻ với bạn bè và đồng nghiệp của mình nhé!

Happy coding! 😎 👍🏻 🚀 🔥

This post is licensed under CC BY 4.0 by the author.