openplanning

Hướng dẫn và ví dụ Java SortedSet

  1. SortedSet
  2. Examples
  3. Phần tử null
  4. subSet(E fromElement, E toElement)
  5. headSet(E toElement)
  6. tailSet(E fromElement)
  7. spliterator()
  8. first()
  9. last()

1. SortedSet

SortedSet là một interface con của Set, vì vậy nó có đầy đủ các đặc điểm của Set. Điều khác biệt là các phần tử của SortedSet được sắp xếp tăng dần theo thứ tự tự nhiên của chúng hoặc theo một Comparator được cung cấp.
SortedSet sắp xếp các phần tử theo thứ tự tăng dần.
public interface SortedSet<E> extends Set<E>
Sau đây là so sánh giữa SetSortedSet:
Set<E>
SortedSet<E> / NavigableSet<E>
Không cho phép phần tử trùng lặp. Nếu bạn cố tình thêm 1 phần tử trùng lặp vào Set hành động này sẽ bị bỏ qua.
Không cho phép phần tử trùng lặp. Nếu bạn cố tình thêm 1 phần tử trùng lặp vào SortedSet hành động này sẽ bị bỏ qua.
Cho phép nhiều nhất một phần tử null.
Cho phép nhiều nhất một phần tử null.
Thứ tự của các phần tử không được đảm bảo.
Thứ tự của các phần tử được đảm bảo.
Tất cả các phần tử của SortedSet phải là kiểu Comparable (có thể so sánh) hoặc bạn phải cung cấp một Comparator (bộ so sánh) cho SortedSet để nó so sánh các phần tử với nhau. Ngược lại, ClassCastException sẽ bị ném ra.
Như vậy, khi bạn thêm một phần tử vào SortedSet bạn không thể chỉ định vị trí của nó. Vị trí của phần tử được chèn vào được quyết định bởi thứ tự tự nhiên của nó hoặc Comparator được cung cấp.
SortedSet Methods
Comparator<? super E> comparator()

SortedSet<E> subSet(E fromElement, E toElement)

SortedSet<E> headSet(E toElement)

SortedSet<E> tailSet(E fromElement)

E first()  

E last()  

default Spliterator<E> spliterator()

2. Examples

Lớp Employee dưới đây mô phỏng một nhân viên với các thông tin fullNamesalary. Lớp Employee thi hành interface Comparable<Employee>, điều này có nghĩa là các đối tượng Employee có khả năng so sánh với nhau.
Hai đối tượng Employee có thể so sánh được với nhau theo quy tắc: So sánh dựa trên salary, nếu chúng có cùng salary thì fullName sẽ được sử dụng để so sánh.
Employee.java
package org.o7planning.bean;

public class Employee implements Comparable<Employee> {

    private String fullName;
    private float salary;

    public Employee(String name, float salary) {
        this.fullName = name;
        this.salary = salary;
    }

    public String getFullName() {
        return fullName;
    }

    public float getSalary() {
        return salary;
    }
    
    // Implements method of Comparable<Employee>
    @Override
    public int compareTo(Employee o) {
        float delta = this.salary - o.salary;
        if (delta > 0) {
            return 1;
        } else if (delta < 0) {
            return -1;
        }
        return this.fullName.compareTo(o.fullName);
    }
}
Comparable<Employee>
Ví dụ: Sử dụng TreeSet để lưu trữ các đối tượng Employee, chúng sẽ được sắp xếp theo thứ tự tăng dần.
SortedSetEx1.java
package org.o7planning.sortedset.ex;

import java.util.SortedSet;
import java.util.TreeSet;

import org.o7planning.bean.Employee;

public class SortedSetEx1 {

    public static void main(String[] args) {
        Employee e1 = new Employee("Tom A", 5000);
        Employee e2 = new Employee("Jerry A", 1000);
        Employee e3 = new Employee("Tom B", 1000);
        Employee e4 = new Employee("Jerry B", 5000);
        Employee e5 = new Employee("Donald A", 1000);
        
        SortedSet<Employee> employees = new TreeSet<Employee>();
        
        employees.add(e1);
        employees.add(e2);
        employees.add(e3);
        employees.add(e4);
        employees.add(e5);

        for(Employee e: employees)  {
            System.out.println(e.getSalary() + " / " + e.getFullName());
        }
    }
}
Output:
1000.0 / Donald A
1000.0 / Jerry A
1000.0 / Tom B
5000.0 / Jerry B
5000.0 / Tom A
Comparable<String>
Các đối tượng String cũng có thể so sánh được với nhau dựa trên Alphabet.
SortedSetEx2.java
package org.o7planning.sortedset.ex;

import java.util.SortedSet;
import java.util.TreeSet;

public class SortedSetEx2 {

    public static void main(String[] args) {   
        SortedSet<String> flowers = new TreeSet<String>();
        
        flowers.add("Rose");
        flowers.add("Lily");
        flowers.add("Tulip");
        flowers.add("Orchid");
        flowers.add("Carnation");
        flowers.add("Hyacinth");
        flowers.add("Peruvian");

        for(String flower: flowers)  {
            System.out.println(flower);
        }
    }  
}
Output:
Carnation
Hyacinth
Lily
Orchid
Peruvian
Rose
Tulip
Comparator<E>
Lớp Staff dưới đây không thi hành interface Comparable, vì vậy các đối tượng Staff không thể so sánh với nhau. Nếu muốn lưu trữ các đối tượng Staff trong một SortedSet bạn cần phải cung cấp một Comparator.
Staff.java
package org.o7planning.bean;

public class Staff {
    private String fullName;
    private float salary;
    public Staff(String fullName, float salary) {
        super();
        this.fullName = fullName;
        this.salary = salary;
    }
    public String getFullName() {
        return fullName;
    }
    public float getSalary() {
        return salary;
    }
}
Lớp MyStaffComparator cho phép so sánh 2 đối tượng Staff dựa trên salaryfullName.
MyStaffComparator.java
package org.o7planning.sortedset.ex;

import java.util.Comparator;

import org.o7planning.bean.Staff;

public class MyStaffComparator implements Comparator<Staff> {

    @Override
    public int compare(Staff o1, Staff o2) {
        float delta = o1.getSalary() - o2.getSalary();
        if (delta > 0) {
            return 1;
        } else if (delta < 0) {
            return -1;
        }
        return o1.getFullName().compareTo(o2.getFullName());
    }
}
SortedSetEx3.java
package org.o7planning.sortedset.ex;

import java.util.SortedSet;
import java.util.TreeSet;

import org.o7planning.bean.Staff;

public class SortedSetEx3 {

    public static void main(String[] args) {
        Staff e1 = new Staff("Tom A", 5000);
        Staff e2 = new Staff("Tom A", 2000);
        Staff e3 = new Staff("Jerry A", 1000);
        Staff e4 = new Staff("Tom B", 1000);
        Staff e5 = new Staff("Jerry B", 5000);
        Staff e6 = new Staff("Donald A", 1000);

        // Custom Comparator.
        MyStaffComparator comparator = new MyStaffComparator();
        // A SortedSet with specified Comparator.
        SortedSet<Staff> employees = new TreeSet<Staff>(comparator);

        employees.add(e1);
        employees.add(e2);
        employees.add(e3);
        employees.add(e4);
        employees.add(e5);
        employees.add(e6);

        for (Staff e : employees) {
            System.out.println(e.getSalary() + "/" + e.getFullName());
        }
    }
}
Output:
1000.0/Donald A
1000.0/Jerry A
1000.0/Tom B
2000.0/Tom A
5000.0/Jerry B
5000.0/Tom A
Comparator là một functional interface, vì vậy bạn có thể tạo ra đối tượng Comparator theo cú pháp Lambda. OK, chúng ta viết lại ví dụ trên ngắn gọn hơn:
SortedSetEx3A.java
package org.o7planning.sortedset.ex;

import java.util.Comparator;
import java.util.SortedSet;
import java.util.TreeSet;

import org.o7planning.bean.Staff;

public class SortedSetEx3A {

    public static void main(String[] args) {
        Staff e1 = new Staff("Tom A", 5000);
        Staff e2 = new Staff("Tom A", 2000);
        Staff e3 = new Staff("Jerry A", 1000);
        Staff e4 = new Staff("Tom B", 1000);
        Staff e5 = new Staff("Jerry B", 5000);
        Staff e6 = new Staff("Donald A", 1000);

        // Custom Comparator.
        Comparator<Staff> comparator = (s1, s2) -> {
            float delta = s1.getSalary() - s2.getSalary();
            if (delta > 0) {
                return 1;
            } else if (delta < 0) {
                return -1;
            }
            return s1.getFullName().compareTo(s2.getFullName());
        };
        // A SortedSet with specified Comparator.
        SortedSet<Staff> employees = new TreeSet<Staff>(comparator);

        employees.add(e1);
        employees.add(e2);
        employees.add(e3);
        employees.add(e4);
        employees.add(e5);
        employees.add(e6);

        for (Staff e : employees) {
            System.out.println(e.getSalary() + "/" + e.getFullName());
        }
    }
}

3. Phần tử null

Đặc tả của interface SortedSetNavigableSet hoàn toàn không nói đến phần tử null, điều này có nghĩa là chúng có thể cho phép nhiều nhất một phần tử null (Thừa kế từ đặc tả của interface Set). Như vậy SortedSetNavigabletSet cho phép phần tử null hay không phụ thuộc vào lớp thi hành các interface này.
Trong Java Collection Framework. Lớp TreeSet thi hành interface NavigableSet, nó cho phép phần tử null nếu bạn cung cấp cho nó một Comparator để xử lý việc so sánh phần tử null với các phần tử khác của nó. Trong khi đó, ConcurrentSkipListSet cũng thi hành interface NavigableSet nhưng không cho phép phần tử null trong bất kỳ tình huống nào.
Hãy xem một ví dụ, TreeSet và phần tử null.
Circle.java
package org.o7planning.bean;

public class Circle  {
    private double radius;

    public Circle(double radius) {
        super();
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }
}
Lớp CircleComparator thi hành interface Comparator<Circle>, nó có thể so sánh 2 đối tượng Circle, kể cả đối tượng null:
CircleComparator.java
package org.o7planning.sortedset.ex;

import java.util.Comparator;

import org.o7planning.bean.Circle;

public class CircleComparator implements Comparator<Circle> {

    @Override
    public int compare(Circle o1, Circle o2) {
        if (o1 == null && o2 == null) {
            return 0;
        }
        if (o1 == null) {
            return -1; // o1 < o2
        } else if (o2 == null) {
            return 1; // o1 > o2
        }
        double delta = o1.getRadius() - o2.getRadius();
        if (delta < 0) {
            return -1; // o1 < o2
        } else if (delta > 0) {
            return 1; // o1 > o2
        }
        return 0;
    }
}
Ví dụ: Một đối tượng TreeSet chứa phần tử null:
SortedSet_null_element_ex1.java
package org.o7planning.sortedset.ex;

import java.util.TreeSet;

import org.o7planning.bean.Circle;

public class SortedSet_null_element_ex1 {

    public static void main(String[] args) {
        Circle c1 = new Circle(3);
        Circle c2 = new Circle(5);
        Circle c3 = new Circle(9);
        Circle c4 = new Circle(7);

        // Create a SortedSet with provided Comparator.
        TreeSet<Circle> set = new TreeSet<Circle>(new CircleComparator());

        set.add(null); // Add null Element
        set.add(c1);
        set.add(c2);
        set.add(c3);
        set.add(c4);

        for (Circle c : set) {
            System.out.println("Circle: " + (c == null?null : c.getRadius()));
        }
    }
}
Output:
Circle: null
Circle: 3.0
Circle: 5.0
Circle: 7.0
Circle: 9.0

4. subSet(E fromElement, E toElement)

public SortedSet<E> subSet(E fromElement, E toElement)
Trả về chế độ xem của một phần của SortedSet này có các phần tử nằm trong khoảng từ fromElement đến toElement (fromElement =< element < toElement). (Nếu fromElementtoElement bằng nhau, SortedSet trả về là rỗng).
SortedSet trả về có liên hệ với SortedSet hiện tại, các thay đổi trên SortedSet này có ảnh hưởng tới SortedSet kia và ngược lại.
SortedSet_subSet_ex1.java
package org.o7planning.sortedset.ex;

import java.util.SortedSet;
import java.util.TreeSet;

public class SortedSet_subSet_ex1 {

    public static void main(String[] args) {  
        SortedSet<String> mySet = new TreeSet<String>();
        
        mySet.add("A");
        mySet.add("B");
        mySet.add("C");
        mySet.add("D");
        mySet.add("E");

        // A Sub Set
        SortedSet<String> subSet = mySet.subSet("B", "C1");
        
        System.out.println(" -- subSet --");
        for(String s: subSet)  {
            System.out.println(s);
        }
        
        subSet.add("B1");
        subSet.add("B2");
        
        System.out.println(" -- subSet (after adding elements to subSet) --");
        for(String s: subSet)  {
            System.out.println(s);
        }
        
        System.out.println(" -- mySet (after adding elements to subSet) --");
        for(String s: mySet)  {
            System.out.println(s);
        }
    }
}
Output:
-- subSet --
B
C
 -- subSet (after adding elements to subSet) --
B
B1
B2
C
 -- mySet (after adding elements to subSet) --
A
B
B1
B2
C
D
E

5. headSet(E toElement)

public SortedSet<E> headSet(E toElement)
Trả về chế độ xem của một phần của SortedSet này có các phần tử nhỏ hơn so với toElement. (element < toElement)
SortedSet trả về có liên hệ với SortedSet hiện tại, các thay đổi trên SortedSet này có ảnh hưởng tới SortedSet kia và ngược lại.
Ví dụ:
SortedSet_headSet_ex1.java
package org.o7planning.sortedset.ex;

import java.util.SortedSet;
import java.util.TreeSet;

public class SortedSet_headSet_ex1 {

    public static void main(String[] args) {
        SortedSet<String> mySet = new TreeSet<String>();

        mySet.add("A");
        mySet.add("B");
        mySet.add("C");
        mySet.add("D");
        mySet.add("D1");
        mySet.add("E");

        // A Head Set (elements < "D1")
        SortedSet<String> headSet = mySet.headSet("D1");

        System.out.println(" -- headSet --");
        for (String s : headSet) {
            System.out.println(s);
        }
    }
}
Output:
-- headSet --
A
B
C
D

6. tailSet(E fromElement)

public SortedSet<E> tailSet(E fromElement)
Trả về chế độ xem của một phần của SortedSet này có các phần tử lớn hơn hoặc bằng fromElement. (element >= fromElement).
SortedSet trả về có liên hệ với SortedSet hiện tại, các thay đổi trên SortedSet này có ảnh hưởng tới SortedSet kia và ngược lại.

7. spliterator()

public default Spliterator<E> spliterator()
  • Hướng dẫn và ví dụ Java Spliterator

8. first()

public E first()
Trả về phần tử đầu tiên (nhỏ nhất) của SortedSet.

9. last()

public E last()
Trả về phần tử cuối cùng (lớn nhất) của SortedSet.

Các hướng dẫn Java Collections Framework

Show More