Trong bài viết này, mình sẽ hướng dẫn các bạn cách sắp xếp các phần tử trong một đối tượng Map sử dụng đối tượng Stream và đối tượng Collectors trong Java bằng key và bằng value.
Ví dụ mình có một đối tượng Map như sau:
1 2 3 4 |
Map<String, Integer> studentMap = new HashMap<>(); studentMap.put("Khanh", 31); studentMap.put("Thanh", 25); studentMap.put("Dung", 35); |
Trước Java 8, để sắp xếp các phần tử của đối tượng Map này bằng key, chúng ta có thể sử dụng phương thức static Collections.sort() của class Collections như sau:
1 2 3 4 5 6 7 8 9 |
List<Map.Entry<String, Integer>> students = new ArrayList<Map.Entry<String, Integer>>(); students.addAll(studentMap.entrySet()); Collections.sort(students, new Comparator<Map.Entry<String, Integer>>() { @Override public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { return o1.getKey().compareTo(o2.getKey()); } }); |
Kết quả:
Làm tương tự nếu các bạn muốn sử dụng phương thức static sort() của class Collections để sắp xếp các phần tử trong đối tượng Map theo value.
Kể từ Java 8 trở đi, các bạn còn có một cách khác nữa đó là sử dụng đối tượng Stream với đối tượng Collectors.
Chúng ta sẽ tạo mới đối tượng Stream từ đối tượng Map rồi sau đó sử dụng các phương thức sorted() và collect() của đối tượng Stream này để sắp xếp.
Ví dụ mình cần sắp xếp các phần tử của đối tượng Map theo key thì mình sẽ code như sau:
1 2 3 4 |
Map<String, Integer> students = studentMap.entrySet() .stream() .sorted((o1, o2) -> o1.getKey().compareTo(o2.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new)); |
Ở đây, phương thức sorted() đóng vai trò là một intermediate operation trong Stream pipeline. Tham số của phương thức này là một đối tượng Comparator cho phép chúng ta có thể định nghĩa tiêu chí cần sắp xếp là gì. Chúng ta còn có thể sử dụng phương thức static comparingByKey() của class Map.Entry để sắp xếp theo key như sau:
1 2 3 4 |
Map<String, Integer> students = studentMap.entrySet() .stream() .sorted(Map.Entry.comparingByKey()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new)); |
Còn phương thức collect() sẽ đóng vai trò là một terminal operation trong Stream pipeline. Tham số của phương thức này là một đối tượng Collectors và chúng ta sẽ sử dụng phương thức toMap() của đối tượng Collectors này để xây dựng một đối tượng Map mới sau khi sắp xếp.
Phương thức toMap() của đối tượng Collectors có một số phương thức overload như sau:
1 |
toMap(Function keyMapper, Function valueMapper) |
1 |
toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) |
1 |
toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction, Supplier mapSupplier) |
Trong đó tham số đầu và thứ hai của phương thức toMap() là những thể hiện của interface Function được sử dụng để generate key và value cho đối tượng Map mới.
Tham số thứ 3 của của phương thức toMap() này là một tham số optional, được sử dụng trong trường hợp key của đối tượng Map mới có những giá trị duplicate. Sử dụng đối tượng BinaryOperator, chúng ta có thể chọn giá trị của những key bị duplicate này, tránh IllegalStateException. Ở ví dụ trên, (oldValue, newValue) -> oldValue có nghĩa trong trường hợp key bị duplicate, chúng ta sẽ lấy giá trị của key trước đó.
Tham số cuối cùng của phương thức toMap() cũng là một tham số optional, cho phép chúng ta định nghĩa đối tượng Map mới là thể hiện của class nào. Mặc định nếu các bạn không sử dụng tham số này thì class đó sẽ là HashMap.
Kết quả của ví dụ trên như sau:
Để sắp xếp các phần tử trong một đối tượng Map theo value, chúng ta có thể sử dụng phương thức static comparingByValue() của đối tượng Map.Entry như sau:
1 2 3 4 |
Map<String, Integer> students = studentMap.entrySet() .stream() .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new)); |
Ở đây, mình sử dụng thêm phương thức static reverseOrder() của class Comparator để sắp xếp các giá trị này giảm dần.
Kết quả: