SortedSet是一个Set,以升序维持元素顺序,按照元素的自然顺序或者根据Comparator提供的在SortedSet的创建时间排序。除了正常的Set操作, SortedSet接口提供了如下操作:
SortedSet接口的代码如下:
public interface SortedSet<E> extends Set<E> {
// Range-view
SortedSet<E> subSet(E fromElement, E toElement);
SortedSet<E> headSet(E toElement);
SortedSet<E> tailSet(E fromElement);
// Endpoints
E first();
E last();
// Comparator access
Comparator<? super E> comparator();
}
SortedSet从set继承的操作在有序set和普通set上大部分相同,但是又两个例外:
尽管接口没有保证它,但是java平台中SortedSet的实现类的toString方法会返回一个字符串,它顺序包含有序集合中的元素。
按照惯例,所有的Collection的通用实现提供了一个标准的转换构造器来得到Collection;SortedSet实现也不例外。在TreeSet中,这个构造器创建了一个实例,通过自然顺序对自己的元素进行了排序。这可能是一个错误,SortedSet转换构造器将会动态的检查指定的集合是不是SortedSet实例,如果是,根据同样的标准(comparator或者自然顺序)对新的TreeSet进行排序。因为TreeSet也使用了它这个方法,TreeSet提供了构造器接收一个SortedSet,并且返回根据相同标准对元素排序的TreeSet。注意这是参数的编译时类型,不是运行时类型,这取决于它们的两个构造器哪个被调用(并且是否保存了排序标准)。
按照惯例,SortedSet也提供了一个接收Comparator返回一个按照指定的Comparator排序的空Set的构造器。 如果传输null给这个构造器,他会返回一个根据自然顺序排序的的set。
范围视图操作与List接口中提供的类似,但是有一个大不同。SortedSet的范围视图操作会保持有效,即使它背后的集合被直接修改。 这是可能的,因为在元素空间中sorted set的范围视图的端点是绝对点,而不是背后set中的特定元素, list的情况也一样。排序集合的范围视图实际上只是元素空间指定部分中任意集合部分的窗口。对范围视图的修改会反馈到它背后的集合,反之亦然。因此,长时间使用范围视图是没问题的,不像list中的范围视图。
SortedSet提供了三种范围视图操作。第一个是subSet,传入两个端点,像subList一样。端点不是索引,而是对象,并且必须与已排序集合中的元素进行比较,使用集合的比较器或其元素的自然顺序(无论集合使用哪种方式来排序本身)。同subList一样,这个范围也是半开放,包含下端点不包含上端点。
因此,下面的代码将告诉你名为dictionary的sortedSet包含的字符串在doordell和pickle之间包含多少单词,包括doorbell但不包含pickle。
int count = dictionary.subSet("doorbell", "pickle").size();
同样的方式,下面的一行代码删除了所有已字母f开头的元素
dictionary.subSet("f", "g").clear();
一个相似的技巧可以被用来打印以每个字母开头的单词有多少个。
for (char ch = 'a'; ch <= 'z'; ) {
String from = String.valueOf(ch++);
String to = String.valueOf(ch);
System.out.println(from + ": " + dictionary.subSet(from, to).size());
}
假设你想查看一个包含两个端点的闭区间而不是一个开区间。如果元素类型允许对元素空间中给定的值的后续值(后继/ successor of)进行计算,则只需从lowEndpoint到successor(highEndpoint)请求subSet, 虽然他并不完全明显。在String的自然顺序中字符串s的后继值是s+"\0",它是s后面追加了一个空字符。
因此,下面的一行代码将告诉你在字典中介于doorbell和pickle包含多少单词,包括doorbell和pickle。
count = dictionary.subSet("doorbell\0", "pickle").size();
SortedSet还包含两个范围视图操作(headSet和tailSet),它们两都接收一个对象参数。前者返回备份SortedSet初始部分的视图,直到但不包含指定的对象。后者返回备份SortedSet最后一部分的视图,以指定元素开始并且包含备份SortedSet的末尾。因此下面的代码允许你将字典看作两个不相交体a-m和n-z(disjoint volumes)。
SortedSet<String> volume1 = dictionary.headSet("n");
SortedSet<String> volume2 = dictionary.tailSet("n");
SortedSet接口包含返回有序集合中第一个和最后一个元素的操作,不出你所料叫做first和last。除了明显的用途,last还允许解决SortedSet接口中的缺陷。你想对SortedSet做的一件事就是进入Set的内部并向前或向后迭代。从内部向前很容易。仅仅是获取一个tailSet并对其进行迭代。不幸的是,没有简单的办法向后进行。
下面的惯用语法获取在元素空间中小于指定元素o的第一个元素。
Object predecessor = ss.headSet(o).last();
这是从已排序集合内部某一个点向后移动一个元素的好方法,他可以重复应用于向后迭代,但是这是非常抵消的,因为需要查找返回的每一个元素。
SortedSet接口包含一个叫做commparator的方法访问器,它返回用作对集合排序的比较器,或者null如果set根据自然顺序对他的元素进行排序。提供此方法以便于复制已排序集合的相同的顺序到新的集合。它由前面描述的SortedSet的构造器使用。