Hướng dẫn và ví dụ Java Set
1. Set
Set là một interface nằm trong nền tảng tập hợp của Java (Java Collection Framework), và là một interface con của Collection vì vậy nó có đầy đủ các tính năng của một Collection.
Setlà một Collection không tuần tự (unordered Collection), không cho phép các phần tử trùng lặp, và có thể chứa nhiều nhất 1 phần tử null. Nếu bạn cố tình thêm một phần tử trùng lặp vào Set hành động này sẽ bị bỏ qua, Set sẽ không thay đổi.
public interface Set<E> extends Collection<E>
SortedSet là interface con của Set, nó có khả năng tự động xắp xếp các phần tử theo thứ tự tự nhiên của chúng hoặc dựa trên một Comparator được cung cấp.
- Collection
- Queue
- List
- SortedSet
- NavigableSet
- TransferQueue
- BlockingQueue
- BlockingDeque
- Deque
Hệ thống phân cấp các lớp thi hành (implement) interface Set.
- HashSet
- LinkedHashSet
- TreeSet
- ConcurrentSkipListSet
- CopyOnWriteArraySet
- Spliterators
- EnumSet
Các phương thức của interface Set:
Set interface
boolean add(E e)
boolean addAll(Collection<? extends E> c)
void clear()
boolean contains(Object o)
boolean containsAll(Collection<?> c)
boolean equals(Object o)
int hashCode()
boolean isEmpty()
int size()
boolean remove(Object o)
boolean removeAll(Collection<?> c)
boolean retainAll(Collection<?> c)
Object[] toArray()
<T> T[] toArray(T[] a)
Iterator<E> iterator()
default Spliterator<E> spliterator()
static <E> Set<E> copyOf(Collection<? extends E> coll)
static <E> Set<E> of()
static <E> Set<E> of(E e1)
static <E> Set<E> of(E... elements)
static <E> Set<E> of(E e1, E e2)
static <E> Set<E> of(E e1, E e2, E e3)
static <E> Set<E> of(E e1, E e2, E e3, E e4)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
2. Simple Examples
Set là một interface, vì vậy để tạo một đối tượng Set bạn cần tạo thông qua một lớp thi hành nó, chẳng hạn HashSet, LinkedHashSet, TreeSet,..
Ví dụ dưới đây chúng ta tạo một đối tượng HashSet với sức chứa (capacity) ban đầu là 10 phần tử, và sức chứa sẽ tăng lên 80% nếu số phần tử của nó vượt quá sức chứa hiện tại.
SetEx1.java
package org.o7planning.set.ex;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetEx1 {
public static void main(String[] args) {
Set<String> set = new HashSet<String>(10, (float) 0.8);
set.add("One");
set.add("Two");
set.add("Three");
Iterator<String> it1 = set.iterator();
while (it1.hasNext()) {
System.out.println(it1.next());
}
System.out.println(" ----- ");
// When duplication occurs.
// It will add new element and remove old element.
set.add("Two");
set.add("Four");
Iterator<String> it2 = set.iterator();
while (it2.hasNext()) {
System.out.println(it2.next());
}
}
}
Chú ý rằng: Set là một Collection không có thứ tự (unordered Collection) nên bạn có thể nhận được một kết quả hơi khác khi in các phần tử ra màn hình Console.
Output:
One
Two
Three
-----
One
Four
Two
Three
Array --> Set?
Ví dụ chuyển đổi một mảng thành một đối tượng Set.
ArrayToSetEx.java
package org.o7planning.set.ex;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class ArrayToSetEx {
public static void main(String[] args) {
Integer[] sourceArray = { 0, 3, 5, 3, 4, 5 };
Set<Integer> targetSet = new HashSet<Integer>(Arrays.asList(sourceArray));
for(Integer i : targetSet) {
System.out.println(i);
}
}
}
Output:
0
3
4
5
3. stream()
Set là một interface con của Collection, vì vậy nó được thừa kế phương thức stream(). Truy cập vào các phần tử của một Collection thông qua Stream sẽ giúp code của bạn ngắn gọn và dễ hiểu hơn:
- Collection
- Stream
Set_stream.java
package org.o7planning.set.ex;
import java.util.HashSet;
import java.util.Set;
public class Set_stream {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("a1");
set.add("b1");
set.add("a2");
set.add("c1");
set.add("d1");
set.add("e1");
set.stream() //
.map(String::toUpperCase) // to upsercase
.filter(s -> !s.startsWith("A")) // Not starts with "A".
.forEach(System.out::println);
}
}
Output:
E1
D1
C1
B1
4. iterator()
iterator() là phương thức thừa kế từ Collection, nó trả về một đối tượng Iterator để lặp (iterate) trên các phần tử của Collection.
Iterator<E> iterator()
Set_iterator.java
package org.o7planning.set.ex;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Set_iterator {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("a1");
set.add("b1");
set.add("a2");
Iterator<String> ite = set.iterator();
while(ite.hasNext()) {
System.out.println(ite.next());
}
}
}
Output:
a1
a2
b1
5. Set kiểm tra trùng lặp thế nào?
Set là một Collection không cho phép chứa các phần tử trùng lặp, nếu bạn cố tình thêm một phần tử trùng lặp vào Set, hành động này sẽ bị bỏ qua. Vậy câu hỏi đặt ra là làm thế nào để "Set" kiểm tra sự trùng lặp?
SortedSet là một interface con của Set. Trong phần này chúng ta chỉ đề cập tới các kiểu Set thuần thuý (không phải là SortedSet). Các lớp đại diện cho một Set thuần thuý là HashSet, LinkedHashSet, CopyOnWriteArraySet, EnumSet.
Cách SortedSet kiểm tra sự trùng lặp khác biệt hoàn toàn với Set thuần thuý, và được đề cập trong bài viết dưới đây:
HashSet / LinkedHashSet
HashSet (và LinkedHashSet) sẽ so sánh hashcode (mã băm) của 2 phần tử, sau đó so sánh trực tiếp 2 phần tử thông qua phương thức equals của chúng.
Hãy xem 2 ví dụ HashSetDupTest1 & HashSetDupTest2 dưới đây để hiểu hơn về nhận xét trên.
HashSetDupTest1.java
package org.o7planning.set.test;
import java.util.HashSet;
import java.util.Set;
public class HashSetDupTest1 {
public static class Student {
private int studentId;
private String studentName;
public Student(int studentId, String studentName) {
this.studentId = studentId;
this.studentName = studentName;
}
public int getStudentId() {
return studentId;
}
public String getStudentName() {
return studentName;
}
@Override
public boolean equals(Object other) {
if(other == null || !(other instanceof Student)) {
return false;
}
Student o = (Student) other;
return this.studentId == o.studentId;
}
}
public static void main(String[] args) {
Student s1 = new Student(1, "Tom");
Student s2 = new Student(2, "Jerry");
Student s3 = new Student(1, "Tom Cat"); // Same Id with s1.
Set<Student> set = new HashSet<Student>();
set.add(s1);
set.add(s2);
set.add(s3);
for(Student s: set) {
System.out.printf("Student Id: %d / Name: %s (Hashcode: %s)\n", //
s.getStudentId(),s.getStudentName(),s.hashCode());
}
}
}
Output:
Student Id: 2 / Name: Jerry (Hashcode: 474675244)
Student Id: 1 / Name: Tom Cat (Hashcode: 932583850)
Student Id: 1 / Name: Tom (Hashcode: 1586600255)
Sửa lại ví dụ trên bằng cách ghi đè (override) phương thức hashCode() trong lớp Student:
HashSetDupTest2.java
package org.o7planning.set.test;
import java.util.HashSet;
import java.util.Set;
public class HashSetDupTest2 {
public static class Student {
private int studentId;
private String studentName;
public Student(int studentId, String studentName) {
this.studentId = studentId;
this.studentName = studentName;
}
public int getStudentId() {
return studentId;
}
public String getStudentName() {
return studentName;
}
@Override
public boolean equals(Object other) {
if(other == null || !(other instanceof Student)) {
return false;
}
Student o = (Student) other;
return this.studentId == o.studentId;
}
@Override
public int hashCode() { // -----> Override hashCode() method.
return this.studentName.charAt(0);
}
}
public static void main(String[] args) {
Student s1 = new Student(1, "Tom"); // Hashcode: 84 ('T')
Student s2 = new Student(1, "Tom Cat"); // Hashcode: 84 ('T')
Student s3 = new Student(2, "Jerry"); // Hashcode: 74 ('J')
Student s4 = new Student(4, "Daffy"); // Hashcode: 68 ('D')
Student s5 = new Student(5, "Donald"); // Hashcode: 68 ('D')
Set<Student> set = new HashSet<Student>();
set.add(s1);
set.add(s2); // a Duplication (Ignored!)
set.add(s3);
set.add(s4);
set.add(s5);
for(Student s: set) {
System.out.printf("Student Id: %d / Name: %s (Hashcode: %s)\n", //
s.getStudentId(),s.getStudentName(),s.hashCode());
}
}
}
Output:
Student Id: 1 / Name: Tom (Hashcode: 84)
Student Id: 4 / Name: Daffy (Hashcode: 68)
Student Id: 5 / Name: Donald (Hashcode: 68)
Student Id: 2 / Name: Jerry (Hashcode: 74)
CopyOnWriteArraySet
CopyOnWriteArraySet so sánh trực tiếp 2 phần tử thông qua phương thức equals của chúng.
Hãy xem 2 ví dụ CopyOnWriteArraySetDupTest1 & CopyOnWriteArraySetDupTest2 dưới đây để hiểu hơn về nhận xét trên.
CopyOnWriteArraySetDupTest1.java
package org.o7planning.set.test;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public class CopyOnWriteArraySetDupTest1 {
public static class Employee {
private int empId;
private String empName;
public Employee(int empId, String empName) {
this.empId = empId;
this.empName = empName;
}
public int getEmpId() {
return empId;
}
public String getEmpName() {
return empName;
}
// Employee class uses equals(Object) method inherited from Object class.
}
public static void main(String[] args) {
Employee s1 = new Employee(1, "Tom");
Employee s2 = new Employee(2, "Jerry");
Employee s3 = new Employee(1, "Tom Cat");
Set<Employee> set = new CopyOnWriteArraySet<Employee>();
set.add(s1);
set.add(s2);
set.add(s3);
for(Employee s: set) {
System.out.printf("Emp Id: %d / Name: %s\n", //
s.getEmpId(),s.getEmpName());
}
}
}
Output:
Emp Id: 1 / Name: Tom
Emp Id: 2 / Name: Jerry
Emp Id: 1 / Name: Tom Cat
Sửa lại ví dụ trên bằng cách ghi đè (override) phương thức equals(Object) trong lớp Employee:
CopyOnWriteArraySetDupTest2.java
package org.o7planning.set.test;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public class CopyOnWriteArraySetDupTest2 {
public static class Employee {
private int empId;
private String empName;
public Employee(int studentId, String studentName) {
this.empId = studentId;
this.empName = studentName;
}
public int getEmpId() {
return empId;
}
public String getEmpName() {
return empName;
}
@Override
public boolean equals(Object other) { // -----> Override equals() method.
if(other == null || !(other instanceof Employee)) {
return false;
}
Employee o = (Employee) other;
return this.empId == o.empId;
}
}
public static void main(String[] args) {
Employee s1 = new Employee(1, "Tom");
Employee s2 = new Employee(2, "Jerry");
Employee s3 = new Employee(1, "Tom Cat");
Set<Employee> set = new CopyOnWriteArraySet<Employee>();
set.add(s1);
set.add(s2);
set.add(s3); // a Duplication.
for(Employee s: set) {
System.out.printf("Emp Id: %d / Name: %s\n", //
s.getEmpId(),s.getEmpName());
}
}
}
Output:
Emp Id: 1 / Name: Tom
Emp Id: 2 / Name: Jerry
6. of(..)
Phương thức tĩnh Set.of(..) trả về một đối tượng Set có kích thước cố định, ngoại lệ sẽ được ném ra nếu các tham số đầu vào trùng lặp. Đối tượng Set này không hỗ trợ các phương thức tuỳ chọn add, remove, set và clear.
static <E> Set<E> of()
static <E> Set<E> of(E e1)
static <E> Set<E> of(E... elements)
static <E> Set<E> of(E e1, E e2)
static <E> Set<E> of(E e1, E e2, E e3)
static <E> Set<E> of(E e1, E e2, E e3, E e4)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
Set_of.java
package org.o7planning.set.ex;
import java.util.Iterator;
import java.util.Set;
public class Set_of {
public static void main(String[] args) {
Set<Integer> set = Set.of(1, 2, 5, 3, 7, 9, 0);
Iterator<Integer> it2 = set.iterator();
while (it2.hasNext()) {
System.out.println(it2.next());
}
}
}
Chú ý rằng: Set là một Collection không có thứ tự (unordered Collection) nên bạn có thể nhận được một kết quả hơi khác khi in các phần tử ra màn hình Console.
Output:
2
3
5
7
9
0
1
7. spliterator()
Tạo một đối tượng Spliterator cho việc duyệt và phân vùng (traversing and partitioning) các phần tử của Set.
default Spliterator<E> spliterator()
Spliterator được sử dụng rộng rãi cho việc duyệt và phân vùng (traversing and partitioning) nhiều nguồn dữ liệu khác nhau như Collection (List, Set, Queue), BaseStream, array.
- Hướng dẫn và ví dụ Java Spliterator
8. toArray(..)
Phương thức toArray(..) trả về một mảng chứa tất cả các phần tử của Set.
Object[] toArray()
<T> T[] toArray(T[] a)
// Java 11, The default method, inherited from Collection.
default <T> T[] toArray(IntFunction<T[]> generator)
Set_toArray.java
package org.o7planning.set.ex;
import java.util.HashSet;
import java.util.Set;
public class Set_toArray {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("a1");
set.add("b1");
set.add("a2");
String[] array = new String[set.size()];
set.toArray(array);
for(String s: array) {
System.out.println(s);
}
}
}
Output:
a1
a2
b1
Các hướng dẫn Java Collections Framework
- Hướng dẫn và ví dụ Java PriorityBlockingQueue
- Hướng dẫn sử dụng nền tảng tập hợp trong Java (Java Collection Framework)
- Hướng dẫn và ví dụ Java SortedSet
- Hướng dẫn và ví dụ Java List
- Hướng dẫn và ví dụ Java Iterator
- Hướng dẫn và ví dụ Java NavigableSet
- Hướng dẫn và ví dụ Java ListIterator
- Hướng dẫn và ví dụ Java ArrayList
- Hướng dẫn và ví dụ Java CopyOnWriteArrayList
- Hướng dẫn và ví dụ Java LinkedList
- Hướng dẫn và ví dụ Java Set
- Hướng dẫn và ví dụ Java TreeSet
- Hướng dẫn và ví dụ Java CopyOnWriteArraySet
- Hướng dẫn và ví dụ Java Queue
- Hướng dẫn và ví dụ Java Deque
- Hướng dẫn và ví dụ Java IdentityHashMap
- Hướng dẫn và ví dụ Java WeakHashMap
- Hướng dẫn và ví dụ Java Map
- Hướng dẫn và ví dụ Java SortedMap
- Hướng dẫn và ví dụ Java NavigableMap
- Hướng dẫn và ví dụ Java HashMap
- Hướng dẫn và ví dụ Java TreeMap
- Hướng dẫn và ví dụ Java PriorityQueue
- Hướng dẫn và ví dụ Java BlockingQueue
- Hướng dẫn và ví dụ Java ArrayBlockingQueue
- Hướng dẫn và ví dụ Java TransferQueue
Show More