List, Set Map trong java

Java Map

Java Map là một phần của collections framework. Đối tượng Java Map được sử dụng để chứa các cặp khóa-giá trị. Java Map không thể chứa các khóa giống hệt nhau tuy nhiên các giá trị giống nhau thì được phép.
Một số đặc điểm về Map trong Java đó là:
  1. Map cung cấp 3 collection views set of keys, set of key-value mappings và collection of values
  2. Map không đảm bảo về thứ tự khớp, tuy nhiên nó lại phụ thuộc vào cách thực hiện. Ví dụ, HashMap không đảm bảo thứ tự khớp nhưng TreeMap thì có.
  3. Map dùng hashCode và các phương thức tương đương trên Khóa cho các phép toán get và put. Do vậy, các class có thể biến đổi sẽ không phù hợp với các khóa của Map.Nếu các giá trị của hashCode hoặc tương đương thay đổi sau put, bạn sẽ không lấy được giá trị đúng trong phép toán get.
  4. Các implementation class phổ biến của Map trong Java là HashMap, Hashtable, TreeMap, ConcurrentHashMap và LinkedHashMap.
  5. AbstractMap class cung cấp skeletal implementation của Map interface, phần lớn các concrete class của Map mở rộng AbstractMap class và các phương thức cần thiết phải implement.

Các phương thức của Java Map

Chúng ta hãy cùng tìm hiểu một số phương thức quan trọng của Map.
  1. int size(): trả về số ;ượng cặp khóa-giá trị trong Map.
  2. boolean isEmpty(): trả về là nếu không có cặp nào, nếu không thì false.
  3. boolean containsValue(Object value): trả về là true nếu có ít nhất một khóa được khớp với một giá trị cụ thể, nếu không thì false.
  4. V get(Object key): trả về giá trị được khớp với khóa đã đâ ra, nếu không có cặp nào thì sẽ trả về null.
  5. V put(K key, V value): thêm các cặp khóa-giá trị vào map. Nếu đã có một giá trị được khớp với khóa này thì thay giá trị. Phương thức này trả về giá trị trước đó tương ứng với khóa, hoặc null nếu khóa không có gì khớp với khóa.
  6. V remove(Object key): loại bỏ giá trị được khớp với khóa khỏi map này nếu nó tồn tại. Trả về giá trị trước đó mà map khớp với khóa, hoặc null nếu map không chứa giá trị nào để khớp với khóa.
  7. void putAll(Map m): Sao chép tất cả các cặp từ một map sang map này.
  8. void clear(): loại bỏ tất cá các cặp khỏi Map.
  9. Set keySet(): trả về Set view của tất cả các khóa trong Map. Key set này được hậu thuẫn bởi Map, vì vậy bất kỳ chỉnh sửa nào trong Map sẽ phản xạ lại key set và ngược lại.
  10. Collection values(): trá về collection view của tất cả các giá trị trong Map. Tập hợp này được hậu thuẫn bởi Map, vì vậy bất kì thay đổi nào trong Map sẽ phản xạ lại tập hợp giá trị và ngược lại.
  11. Set> entrySet(): trả về Set view của các cặp trong Map. Set này được hậu thuẫn bởi Map, vì vậy bất kỳ chỉnh sửa nào trong Map sẽ phản xạ lại trong entry set và ngược lại.

Có một vài phương thức Java Map được giới thiệu trong Java 8.

  1. default V getOrDefault(Object key, V defaultValue): trả về giá trị được khớp với một khóa cụ thể, hoặc defaultValue nếu map không chứa giá trị nào để khớp với khóa.
  2. default void forEach(BiConsumer action): thực hiện action được đưa ra cho mỗi đầu vào của map này.
  3. default void replaceAll(BiFunction function): thay giá trị của mỗi entry với kết quả dẫn hàm được đưa ra cho entry đó.
  4. default V putIfAbsent(K key, V value): nếu một khóa cụ thể chưa được khớp với giá trị (hay được khớp với null), khớp nó với giá trị được đưa ra và trả về null, ngoài ra thì trả về giá trị hiện tại.
  5. default boolean remove(Object key, Object value): Loại bỏ entry cho một khóa cụ thể chỉ khi nó đang được khớp với một giá trị cụ thể.
  6. default boolean replace(K key, V oldValue, V newValue): Thay thế entry cho một khóa cụ thể chỉ khi nó đang được khớp với một giá trị cụ thể.
  7. default V replace(K key, V value): Thay thế entry cho một khóa cụ thể chỉ khi nó đang được khớp với một số giá trị.
  8. default V computeIfAbsent(K key, Function mappingFunction): Nếu khóa cụ thể chưa được khớp vởi một giá trị (hoặc khớp với null), tính toán giá trị của nó sử dụng hàm mapping được đưa ra và nhập nó vòa map này trừ khi null.
  9. default V computeIfPresent(K key, BiFunction remappingFunction): nếu tồn tại giá trị cho một khóa cụ thể và không phải null, tính toán để khớp một giá trị mới cho cặp khóa và giá trị hiện tại được khớp với nó. Nếu hàm trả về null, thì việc khớp giá trị mới sẽ được loại bỏ
  10. default V compute(K key, BiFunction remappingFunction): tính toán để khớp một giá trị mới cho cặp khóa và giá trị hiện tại được khớp với nó (hoặc null nếu không có giá trị nào đang được khớp).
  11. default V merge(K key, V value, BiFunction remappingFunction): nếu một khóa cụ thể chưa được khớp với một giá trị hoặc đang khớp với null, khớp nó với một giá trị không phải null. Ngoài ra, thay thế giá trị được khớp với kết quả của hàm remapping được đưa ra, hoặc loại bỏ nếu kết quả là null.
Bạn sẽ để ý thấy tất cả các phương thức mới được thêm vào Java 8 Map interface là các phương thức mặc định với implementation. Điều này là để đảm bảo không xảy ra các lỗi biên dịch khi các class implement Map interface.

Ví dụ

Dưới đây là ví dụ về một chương trình đơn giản cho Java Map. Chúng ta sẽ sử dụng Map implementation class HashMap cho ví dụ này.

packagecom.journaldev.examples;
importjava.util.Collection;
importjava.util.HashMap;
importjava.util.Map;
importjava.util.Map.Entry;
importjava.util.Set;
publicclassMapExample{
publicstaticvoidmain(String[]args){
Map<String,String>data=newHashMap<>();
data.put("A","A");//putexample
data.put("B","B");
data.put("C","C");
data.put("D",null);//nullvalue
data.put(null,"Z");//nullkey
Stringvalue=data.get("C");//getexample
System.out.println("Key=C,Value="+value);
value=data.getOrDefault("E","DefaultValue");
System.out.println("Key=E,Value="+value);
booleankeyExists=data.containsKey(null);
booleanvalueExists=data.containsValue("Z");
System.out.println("keyExists="+keyExists+",valueExists="+valueExists);
Set<Entry<String,String>>entrySet=data.entrySet();
System.out.println(entrySet);
System.out.println("datamapsize="+data.size());
Map<String,String>data1=newHashMap<>();
data1.putAll(data);
System.out.println("data1mappings="+data1);
StringnullKeyValue=data1.remove(null);
System.out.println("data1nullkeyvalue="+nullKeyValue);
System.out.println("data1afterremovingnullkey="+data1);
Set<String>keySet=data.keySet();
System.out.println("datamapkeys="+keySet);
Collection<String>values=data.values();
System.out.println("datamapvalues="+values);
data.clear();
System.out.println("datamapisempty="+data.isEmpty());
}
}

Output của chương trình trên sẽ là:

Key=C,Value=C
Key=E,Value=DefaultValue
keyExists=true,valueExists=true
[null=Z,A=A,B=B,C=C,D=null]
datamapsize=5
data1mappings={null=Z,A=A,B=B,C=C,D=null}
data1nullkeyvalue=Z
data1afterremovingnullkey={A=A,B=B,C=C,D=null}
datamapkeys=[null,A,B,C,D]
datamapvalues=[Z,A,B,C,null]
datamapisempty=true

Java Set

Java Set là một tập hợp các phần tử (hoặc đối tượng) mà không chứa các phần tử giống hệt nhau. Java Set là một interface mở rộng cho Collection interface. Không như List, Java Set KHÔNG PHẢI là một tập hợp ược sắp xếp, các phần tử của nó KHÔNG CÓ một thứ tự cụ thể. Java SetKHÔNG cung cấp cho bạn quyền quyết định vị trí để chèn một phần tử. Bạn không thể truy cập vào phần tử bằng index và cả tìm kiếm phần tử trong danh sách.

Trong phần này, chúng ta sẽ cùng bàn luận về một số điểm quan trọng của Java Set:
  • Java Set interface không phải là thành viên của Java Collections Framework.
  • Không như List, SetKHÔNG cho phép bạn sao chép các phần tử.
  • Set chỉ cho phép bạn thêm tối đa một phần tử null.
  • Set interface có một phương thức mặc định trong Java 8: spliterator.
  • Không như List và các array, Set KHÔNG hỗ trợ các index hay vị trí các phần tử của nó.
  • Set hỗ trợ Generics và chúng ta nên sử dụng bất cứ khi nào có thể. Sử dụng Generics với Set sẽ tránh được lỗ ClassCastException trong runtime.
  • Chúng ta có thể sử dụng các implementation của Set interface để duy trì các phần tử độc nhất.

Sơ đồ Java Set Class

Java Set interface mở rộng Collection interface. Collection interface mở rộng Iterable interface. Một số Set implementation class thương dùng là HashSet, LinkedHashSet, TreeSet, CopyOnWriteArraySet và ConcurrentSkipListSet. AbstractSet cung cấp một skeletal implementation của Set interface để giảm thiếu công sức implement Set.
List, Set Map trong java

Các phương thức Java Set

Trong phần này chúng ta sẽ cùng tìm hiểu một số phương thức Java Set hữu dụng:
  1. int size(): lấy số phần tử trong Set.
  2. boolean isEmpty(): Kiểm tra xem Set trống hay không.
  3. boolean contains(Object o): Trả về true nếu Set chứa giá trị cụ thể.
  4. Iterator iterator(): Trả về một iterator qua các phần tử trong set này. Các phần tử được trả về không theo thứ tự cụ thể.
  5. Object[] toArray(): Trả về một array chứa tất cả các phần tử trong set này. Nếu set này đưa ra bất kì đảm bảo nào về thứ tự trả về các phần tử bởi iterator của nó, thì phương thức này phải trả về các phần tử theo đúng thứ tự đó.
  6. boolean add(E e): Thêm một phần tử cụ thể vào set này nếu chưa có (phép toán tùy chọn).
  7. boolean remove(Object o): Loại bỏ phần tử từ set này nếu nó tồn tại (phép toán tùy chọn).
  8. boolean removeAll(Collection c): Loại bỏ từ set này tất cả các phần tử của nó được chữa trong một tập hợp cụ thể (phép toán tùy chọn).
  9. boolean retainAll(Collection c): Chỉ giữ lại các phần tử trong set này mà được chưa trong một tập hợp cụ thể (phép toán tùy chọn).
  10. void clear(): Loại bỏ tất cả các phần tử khỏi set.
  11. Iterator iterator(): Trả về một iterator qua các phần tử trong set này.

Chuyển đổi Java Array sang Set

Không như List, chúng ta không thể trực tiếp chuyển đổi Java Set sang một array bởi nó KHÔNG được implement bằng một Array.

Bởi vậy chúng ta không thê sử dụng Arrays class đẻ lấy view của array như là set. Chúng ta có thể đi theo một cách tiếp cận khác, đó là chuyển đổi array dang List sử dụng phương thức Arrays.asList(), sau đó dùng nó để tạo một Set. Bằng cách này, chúng ta có thể chuyển đổi một Java Array sang Set theo 2 cách. Hãy cùng đi tìm hiểu từng cách một bằng các ví dụ đơn giản dưới đây.

Cách 1

Với cách này, đầu tiên chúng ta cần tạo một List với array đã cho và sử dụng nó để tạo một Set.


importjava.util.*;
publicclassArrayToSet{
publicstaticvoidmain(String[]args){
String[]vowels={"a","e","i","o","u"};
Set<String>vowelsSet=newHashSet>(Arrays.asList(vowels));
System.out.println(vowelsSet);
/**
*UnlikeList,SetisNOtbackedbyarray,
*sowecandostructuralmodificationwithoutanyissues.
*/
vowelsSet.remove("e");
System.out.println(vowelsSet);
vowelsSet.clear();
System.out.println(vowelsSet);
}
}

Cách 2
Theo cách này, chúng ta sẽ KHÔNG sử dụng List trung gian để tạo một từ một Array. Trước hết hãy tạo một HashSet trống, sau đó dùng Collections.addAll() để sao chép các phần tử array vào Set.


importjava.util.*;
publicclassArrayToSet2{
publicstaticvoidmain(String[]args){
String[]vowels={"a","e","i","o","u"};
Set<String>vowelsSet=newHashSet<>();
Collections.addAll(vowelsSet,vowels);
System.out.println(vowelsSet);
/**
*UnlikeList,SetisNOtbackedbyarray,
*sowecandostructuralmodificationwithoutanyissues.
*/
vowelsSet.remove("e");
System.out.println(vowelsSet);
vowelsSet.clear();
System.out.println(vowelsSet);
}
}

Output:

Sau khi chạy 2 chương trình trên, chúng ta sẽ có các output như dưới đây.

[a,e,u,i,o]
[a,u,i,o]
[]

Chuyển đổi Java Set sang ArrayTrong phần này, chúng ta sẽ viết một chương trình để chuyển đổi một Set của các String thành một Array của String sử dụng phương thức Set.toArray().

importjava.util.*;
publicclassSetToArray{
publicstaticvoidmain(String[]args){
Set<StringnewHashSet<>();
//addexample
vowelsSet.add("a");
vowelsSet.add("e");
vowelsSet.add("i");
vowelsSet.add("o");
vowelsSet.add("u");
//convertSettoArray
StringstrArray[]=vowelsSet.toArray(newString[vowelsSet.size()]);
System.out.println(Arrays.toString(strArray));
}
}

Output:

Sau khi chạy chương trình trên, chúng ta sẽ có output như dưới đây


[a,e,u,i,o]

Sắp xếp Java Set

Như chúng ta đã biết, Set (HashSet) không hỗ trợ sắp xếp trực tiếp các phần tử. Nó lưu và hiển thị các phần tử của nó theo thứ tự ngẫu nhiên.

Tuy nhiên, chúng ta sẽ có một số cách để sắp xếp các phần tử của nó như sau:

importjava.util.*;

publicclassSetSortingExample{

publicstaticvoidmain(String[]args){
Set<Integer>intsSet=newHashSet<>();
Randomrandom=newRandom();
for(inti=0;i{return(o2-o1);});
System.out.println("ReverseSorting:"+intsList2);

//Approach-3
Set<Integer>sortedSet=newTreeSet<>(intsSet);
System.out.println("SortedSet:"+sortedSet);
}
}

Output:

Sau khi chạy chương trình trên, chúng ta sẽ có output như dưới đây.


[560,864,176,657,135,103,40,123,555,589]
NaturalSorting:[40,103,123,135,176,555,560,589,657,864]
BeforeSorting:[560,864,176,657,135,103,40,123,555,589]
ReverseSorting:[864,657,589,560,555,176,135,123,103,40]
SortedSet:[40,103,123,135,176,555,560,589,657,864]

Các phép toán thông thường trong Java Set

Các phép toán thường thấy của Java Set là add, addAll, clear, size,..v..v... Dưới đây là các ví dụ đơn giản về ứng dụng các phương thức thông thường trong Java Set.

importjava.util.*;
publicclassSetCommonOperations
{
publicstaticvoidmain(Stringargs[])
{
Set<String>vowels=newHashSet<>();
//addexample
vowels.add("A");
vowels.add("E");
vowels.add("I");
//WecannotinsertelementsbasedonindextoaSet
System.out.println(vowels);
Set<String>set=newHashSet<>();
set.add("O");
set.add("U");
//appendingsetelementstoletters
vowels.addAll(set);
System.out.println(vowels);
//clearexampletoemptytheset
set.clear();
//sizeexample
System.out.println("letterssetsize="+vowels.size());
vowels.clear();
vowels.add("E");vowels.add("E");vowels.add("I");vowels.add("O");
System.out.println("GivensetcontainsEelementornot?="+vowels.contains("E"));
}
}

Output:

[A,E,I]
[A,E,U,I,O]
letterssetsize=5
GivensetcontainsEelementornot?=true
JavaSetIterator


Dưới đây là ví dụ về cách lặp qua Java Set.

importjava.util.*;
publicclassSetIteratorExample
{
publicstaticvoidmain(String[]args)
{
Set<Integer>set=newHashSet<>();
for(inti=0;i<5;i++)
set.add(i);
Iteratoriterator=set.iterator();
//simpleiteration
while(iterator.hasNext()){
inti=(int)iterator.next();
System.out.print(i+",");
}
System.out.println("\n"+set);
//modificationofsetusingiterator
iterator=set.iterator();
while(iterator.hasNext()){
intx=(int)iterator.next();
if(x%2==0)iterator.remove();
}
System.out.println(set);
//changingsetstructurewhileiterating
iterator=set.iterator();
while(iterator.hasNext()){
//ConcurrentModificationExceptionhere
intx=(int)iterator.next();
if(x==1)set.add(10);
}
}
}

Chuyển đổi Java Set sang Stream

Dưới đây là phương pháp chuyển một Java Set sang Stream để thực hiện các phép toán theo yêu cầu của chúng ta.

importjava.util.*;
publicclassSetToStream{
publicstaticvoidmain(String[]args){
Set<String>vowelsSet=newHashSet<>();
//addexample
vowelsSet.add("a");
vowelsSet.add("e");
vowelsSet.add("i");
vowelsSet.add("o");
vowelsSet.add("u");
//convertsettostream
vowelsSet.stream().forEach(System.out::println);
}
}
Output:

a
e
u
i
o