1. Set interface trong Java
Set interface trong Java Collections framework giúp lưu trữ một tập hợp (set). Set interface kế thừa từ Collection interface. Set interface không bao gồm 2 phần tử giống nhau còn List interface thì có thể bao gồm các phần tử giống nhau.
Những lớp kế thừa Set interface
Chúng ta cần import java.util.Set
để sử dụng Set interface.
Set<String> animals = new HashSet<>();
Trong ví dụ trên, chúng ta tạo đối tượng animals của lớp HashSet.
Các phương thức của Set interface
Set interface bao gồm các phương thức của Collection interface. Ngoài ra, Set interface còn có những phương thứ khác:
add()
thêm phần tử vào Set.addAll()
thêm tất cả phần tử của một Set vào một Set khác.iterator()
trả về một đối tượng iterator để truy cập các phần tử của Set.remove()
xóa một phần tử trong Set.removeAll()
xóa tất cả phần tử trong Set mà những phần tử này có tồn tại trong một Set khác.retainAll()
giữ lại tất cả những phần tử trong một tập hợp mà những phần tử này có tồn tồn tại trong một Set khác.clear()
xóa tất cả phần tử trong Set.size()
trả về số lượng phần tử trong Set.toArray()
trả về một mảng (array) bao gồm các phần tử của Setcontains()
trả về true nếu Set bao gồm một phần tử nào đó.containsAll()
trả về true nếu Set bao gồm tất cả các phần tử trong một Set nào đó.hashCode()
trả về hash code value, tức là địa chỉ của phần tử trong Set.
2. Lớp HashSet trong Java
Lớp HashSet kế thừa từ Set interface và giúp lưu trữ cấu trúc dữ liệu dạng hash table.
Tạo ra một HashSet
Để tạo ra một HashSet, chúng ta phải import java.util.HashSet
và tạo đối tượng HashSet với cú pháp sau:
HashSet<Type> numbers = new HashSet<>(8, 0.6);
Trong đó, numbers là đối tượng HashSet được tạo ra. Type là kiểu dữ liệu của các phần tử trong HashSet. Lưu ý: Không thể dùng các kiểu dữ liệu nguyên thủy cho HashSet mà phải sử dụng Wrapper Class.
Có 2 tham số khi tạo HashSet trong cú pháp new HashSet<>(10, 0.6);
. Tham số đầu tiên là capacity, tham số thứ 2 là loadFactor.
- capacity được thiết lập là 10. Có nghĩa là HashSet ban đầu chứa được 10 phần tử.
- loadFactor được thiết lập là 0.6. Có nghĩa là khi số lượng phần tử trong HashSet lớn hơn hoặc bằng 60% capacity thì kích thước của HashSet sẽ tăng lên gấp đôi. Ví dụ: kích thước ban đầu của HashSet capacity=10 thì nếu HashSet đã chứa 0.6×10=6 phần tử thì kích thước của HashSet tự động tăng lên capacity=20. Cứ như thế nếu HashSet chứa 0.6×20=12 phần tử thì kích thước HashSet tự động tăng lên capacity=30.
Nếu không khai báo capacity và loadFactor khi khởi tạo HashSet thì capacity mặc định là 16, loadFactor mặc định là 0.75.
//HashSet với default capacity = 16 và default load factor = 0.75
HashSet<Integer> numbers1 = new HashSet<>();
Thêm phần tử vào HashSet
Sử dụng hàm add()
để thêm một phần tử vào HashSet. Sử dụng hàm addAll()
để thêm tất cả phần tử của một HashSet vào một HashSet khác.
import java.util.HashSet;
class Main {
public static void main(String[] args) {
HashSet<Integer> evenNumber = new HashSet<>();
//thêm các phần tử vào HashSet
evenNumber.add(2);
evenNumber.add(4);
evenNumber.add(6);
System.out.println("HashSet: " + evenNumber);
HashSet<Integer> numbers = new HashSet<>();
//thêm các phần tử của HashSet này vào HashSet khác
numbers.addAll(evenNumber);
numbers.add(5);
System.out.println("New HashSet: " + numbers);
}
}
Kết quả
HashSet: [2, 4, 6]
New HashSet: [2, 4, 5, 6]
Truy cập các phần tử trong HashSet
Để truy cập các phần tử trong HashSet, chúng ta có thể sử dụng phương thức iterator()
. Để sử dụng phương thức này cần import java.util.Iterator
.
import java.util.HashSet;
import java.util.Iterator;
class Main {
public static void main(String[] args) {
HashSet<Integer> evenNumber = new HashSet<>();
//thêm các phần tử vào HashSet
evenNumber.add(2);
evenNumber.add(4);
evenNumber.add(6);
System.out.println("HashSet: " + evenNumber);
//hàm iterator() trả về một đối tượng Iterator
Iterator<Integer> iterate = evenNumber.iterator();
System.out.print("HashSet using Iterator: ");
//truy cập các phần tử trong HashSet
while(iterate.hasNext()) {
System.out.print(iterate.next());
System.out.print(", ");
}
}
}
Kết quả
HashSet: [2, 4, 6]
HashSet using Iterator: 2, 4, 6,
Xóa các phần tử trong HashSet
Sử dụng hàm remove()
để xóa một phần tử trong HashSet. Sử dụng hàm removeAll()
để xóa tất cả phần tử trong HashSet mà những phần tử này có tồn tại trong một HashSet khác.
import java.util.HashSet;
class Main {
public static void main(String[] args) {
HashSet<Integer> evenNumber = new HashSet<>();
//thêm các phần tử vào HashSet
evenNumber.add(2);
evenNumber.add(4);
evenNumber.add(6);
System.out.println("HashSet: " + evenNumber);
//sử dụng hàm remove()
boolean value1 = evenNumber.remove(2);
System.out.println("Update HashSet: " + evenNumber);
boolean value2 = evenNumber.removeAll(evenNumber);
System.out.println("Update HashSet: " + evenNumber);
}
}
Kết quả
HashSet: [2, 4, 6]
Update HashSet: [4, 6]
Update HashSet: []
Kết hợp 2 HashSet
Để kết hợp 2 HashSet, chúng ta sử dụng phương thức addAll()
.
import java.util.HashSet;
class Main {
public static void main(String[] args) {
HashSet<Integer> evenNumbers = new HashSet<>();
evenNumbers.add(2);
evenNumbers.add(4);
System.out.println("HashSet1: " + evenNumbers);
HashSet<Integer> numbers = new HashSet<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
System.out.println("HashSet2: " + numbers);
//kết hợp (union) 2 tập hợp HashSet
numbers.addAll(evenNumbers);
System.out.println("Union is: " + numbers);
}
}
Kết quả
HashSet1: [2, 4]
HashSet2: [1, 2, 3]
Union is: [1, 2, 3, 4]
Lấy phần giao của 2 HashSet
Để lấy phần giao của 2 HashSet, chúng ta sử dụng hàm retainAll()
.
import java.util.HashSet;
class Main {
public static void main(String[] args) {
HashSet<Integer> evenNumbers = new HashSet<>();
evenNumbers.add(2);
evenNumbers.add(4);
System.out.println("HashSet1: " + evenNumbers);
HashSet<Integer> numbers = new HashSet<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
System.out.println("HashSet2: " + numbers);
//Lấy phần giao của 2 HashSet
evenNumbers.retainAll(numbers);
System.out.println("Intersection is: " + evenNumbers);
}
}
Kết quả
HashSet1: [2, 4]
HashSet2: [1, 2, 3]
Intersection is: [2]
Lấy phần khác nhau giữa 2 HashSet
Để lấy phần khác nhau giữa 2 HashSet, chúng ta có thể sử dụng hàm removeAll()
.
import java.util.HashSet;
class Main {
public static void main(String[] args) {
HashSet<Integer> evenNumbers = new HashSet<>();
evenNumbers.add(2);
evenNumbers.add(4);
System.out.println("HashSet1: " + evenNumbers);
HashSet<Integer> numbers = new HashSet<>();
numbers.add(2);
numbers.add(3);
System.out.println("HashSet2: " + numbers);
//Lấy phần khác nhau giữa 2 HashSet
evenNumbers.removeAll(numbers);
System.out.println("Difference : " + evenNumbers);
}
}
Kết quả
HashSet1: [2, 4]
HashSet2: [2, 3]
Difference : [4]
Kiểm tra một HashSet có nằm trong một HashSet khác hay không
Để kiểm tra một HashSet có nằm trong của một HashSet khác hay không, chúng ta sử dụng hàm containsAll()
.
import java.util.HashSet;
class Main {
public static void main(String[] args) {
HashSet<Integer> evenNumbers = new HashSet<>();
evenNumbers.add(2);
evenNumbers.add(4);
System.out.println("HashSet1: " + evenNumbers);
HashSet<Integer> numbers = new HashSet<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
System.out.println("HashSet2: " + numbers);
//Kiểm tra evenNumbers có nằm trong numbers hay không
boolean result = numbers.containsAll(evenNumbers);
System.out.println("Is HashSet1 is subset of HashSet2? " + result);
}
}
Kết quả
HashSet1: [2, 4]
HashSet2: [1, 2, 3, 4]
Is HashSet1 is subset of HashSet2? true
Sử dụng HashSet khi nào?
Trong Java, HashSet thường được sử dụng nếu chúng ta phải truy cập các phần tử một cách ngẫu nhiên. Đó là vì các phần tử trong bảng băm được truy cập bằng mã băm (hash code). Mã băm (hash code) của một phần tử là một nhận dạng duy nhất giúp xác định phần tử trong bảng băm.
HashSet không được chứa các phần tử trùng lặp. Do đó, mỗi phần tử tập hợp băm có một mã băm duy nhất.