TreeSet作为Java集合框架中常用的有序集合类,底层基于红黑树结构实现,默认按照元素的自然排序规则排列元素,也可以通过传入自定义比较器来指定排序逻辑。除了基础的元素增删查操作,TreeSet还提供了多个用于范围查询的方法,其中subSet和headSet是最常用的两个,能够帮助我们快速获取集合中指定区间内的元素子集。

TreeSet范围查询的基础前提
要使用subSet和headSet方法进行范围查询,首先需要保证TreeSet中的元素是可比较的,否则会抛出ClassCastException。如果是自定义对象存入TreeSet,要么让对象实现Comparable接口,要么在创建TreeSet时传入Comparator比较器实例。另外范围查询的参数类型需要和TreeSet的元素类型匹配,否则也无法正常查询。
headSet方法详解
headSet方法用于获取TreeSet中小于指定边界元素的所有元素,它有两个重载版本:
headSet(E toElement):返回小于toElement的所有元素,不包含toElement本身headSet(E toElement, boolean inclusive):第二个参数inclusive表示是否包含toElement,true为包含,false为不包含
返回的结果是TreeSet的一个视图,对视图的修改会影响原TreeSet,反之亦然。下面是具体的使用示例:
import java.util.TreeSet;
public class TreeSetHeadSetDemo {
public static void main(String[] args) {
// 创建TreeSet并添加整数元素
TreeSet<Integer> treeSet = new TreeSet<>();
for (int i = 1; i <= 10; i++) {
treeSet.add(i);
}
System.out.println("原TreeSet元素:" + treeSet);
// 使用headSet(E toElement),不包含边界
TreeSet<Integer> headSet1 = (TreeSet<Integer>) treeSet.headSet(6);
System.out.println("小于6的元素(不包含6):" + headSet1);
// 使用headSet(E toElement, boolean inclusive),包含边界
TreeSet<Integer> headSet2 = (TreeSet<Integer>) treeSet.headSet(6, true);
System.out.println("小于等于6的元素(包含6):" + headSet2);
}
}
subSet方法详解
subSet方法用于获取TreeSet中指定区间内的元素,同样有两个重载版本:
subSet(E fromElement, E toElement):返回大于等于fromElement且小于toElement的元素,包含fromElement,不包含toElementsubSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive):fromInclusive表示是否包含起始边界,toInclusive表示是否包含结束边界
同样,subSet返回的也是原TreeSet的视图,对子集的增删操作会同步反映到原集合中。下面是使用示例:
import java.util.TreeSet;
public class TreeSetSubSetDemo {
public static void main(String[] args) {
TreeSet<Integer> treeSet = new TreeSet<>();
for (int i = 1; i <= 10; i++) {
treeSet.add(i);
}
System.out.println("原TreeSet元素:" + treeSet);
// 使用subSet(E fromElement, E toElement),左闭右开
TreeSet<Integer> subSet1 = (TreeSet<Integer>) treeSet.subSet(3, 7);
System.out.println("3到7之间的元素(包含3,不包含7):" + subSet1);
// 使用subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
// 左开右闭
TreeSet<Integer> subSet2 = (TreeSet<Integer>) treeSet.subSet(3, false, 7, true);
System.out.println("3到7之间的元素(不包含3,包含7):" + subSet2);
// 左闭右闭
TreeSet<Integer> subSet3 = (TreeSet<Integer>) treeSet.subSet(3, true, 7, true);
System.out.println("3到7之间的元素(包含3,包含7):" + subSet3);
}
}
两个方法的注意事项
使用subSet和headSet方法时需要注意以下几点:
- 边界参数不能超出TreeSet的元素范围,即使超出也不会报错,只是返回的子集可能为空
- 如果传入的边界元素和集合中的元素类型不匹配,会抛出
ClassCastException - 返回的子集视图不支持添加超出原区间范围的元素,否则会抛出
IllegalArgumentException - 如果TreeSet本身为空,那么无论查询什么范围,返回的子集都是空的
实际场景示例
假设我们需要从存储了学生分数的TreeSet中,查询出及格(60分及以上)且小于90分的分数,可以这样实现:
import java.util.TreeSet;
public class ScoreQueryDemo {
public static void main(String[] args) {
TreeSet<Integer> scores = new TreeSet<>();
scores.add(55);
scores.add(62);
scores.add(78);
scores.add(85);
scores.add(92);
scores.add(45);
scores.add(88);
// 查询60分及以上,90分以下的分数,包含60,不包含90
TreeSet<Integer> passScores = (TreeSet<Integer>) scores.subSet(60, true, 90, false);
System.out.println("及格且小于90分的分数:" + passScores);
}
}
通过上述示例可以看出,合理使用subSet和headSet方法可以非常便捷地实现TreeSet的范围查询需求,开发者只需要根据场景选择合适的重载方法,注意边界参数的含义即可。