o7planning

Java SortedSet Tutorial with Examples

  1. SortedSet
  2. Examples
  3. Null Element
  4. subSet(E fromElement, E toElement)
  5. headSet(E toElement)
  6. tailSet(E fromElement)
  7. spliterator()
  8. first()
  9. last()

1. SortedSet

SortedSet is a subinterface of Set, so it has full characteristics of Set. The difference is that the SortedSet elements are sorted in ascending order according to their natural order or by a provided Comparator.
SortedSet sorts elements in ascending order.
public interface SortedSet<E> extends Set<E>
Here is a comparison between Set and SortedSet:
Set<E>
SortedSet<E> / NavigableSet<E>
Duplicate elements are not allowed. If you intentionally add 1 duplicate element to Set, this action will be ignored.
Duplicate elements are not allowed. If you intentionally add 1 duplicate element to SortdSet, this action will be ignored.
Allow at most one null element.
Allow at most one null element.
The order of the elements is not guaranteed.
The order of the elements is guaranteed.
All elements of SortedSet must be Comparable type, or you must provide a Comparator for SortedSet so that it compares the elements. Otherwise, ClassCastException will be thrown.
Thus, when you add an element to SortedSet, you cannot specify its position. The position of the inserted element is determined by its natural order or Comparator provided.
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

The following Employee class simulates an employee with fullName and salary information. Employee class implements Comparable<Employee> interface, which means that Employee objects are comparable.
Two Employee objects can be compared with each other according to this rule: Comparing by salary, if they have the same salary, fullName will be used to compare.
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>
Example: Using TreeSet to store Employee objects, they will be sorted in ascending order.
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>
String objects are also comparable based on 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>
The following Staff class does not implement Comparable interface, so Staff objects cannot be compared with each other. If you want to store Staff objects in a SortedSet you need to provide a 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;
    }
}
MyStaffComparator class allows to compare 2 Staff objects based on salary and fullName.
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 is a functional interface, so you can create Comparator object in Lambda syntax. OK, let's rewrite the above example more concisely:
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. Null Element

The specification of SortedSet and NavigableSet interface does not mention null elements at all, which means that they can allow at most one null element (Inheriting from the specification of Set interface). So whether SortedSet and NavigabletSet allow null element or not depends on the class implementing these interfaces.
In Java Collection Framework, TreeSet class implements NavigableSet interface, allowing null element if you give it a Comparator to handle null element comparison with its other elements. Meanwhile, ConcurrentSkipListSet also implements NavigableSet interface but does not allow null element in any situation.
Let's look at an example, TreeSet and null element.
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;
    }
}
CircleComparator class implements Comparator<Circle> interface, which can compare 2 Circle objects, including null object:
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;
    }
}
Example: A TreeSet object contains a null element:
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)
Returns a view of the portion of this SortedSet whose elements range from fromElement to toElement (fromElement =< element < toElement). (If fromElement and toElement are equal, the returned SortedSet is empty).
Returned SortedSet is related to the current SortedSet. Changes on one SortedSet affect the other and vice versa.
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)
Returns a view of the portion of this SortedSet whose elements are strictly less than toElement. (element < toElement)
Returned SortedSet is related to the current SortedSet. Changes on one SortedSet affect the other and vice versa.
Example:
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)
Returns a view of the portion of this SortedSet whose elements are greater than or equal to fromElement. (element >= fromElement).
Returned SortedSet is related to the current SortedSet. Changes on one SortedSet affect the other and vice versa.

7. spliterator()

public default Spliterator<E> spliterator()
  • Java Spliterator

8. first()

public E first()
Returns the first element (the smallest) of SortedSet.

9. last()

public E last()
Returns the last element (the largest) of SortedSet.