测试方法
public static void main(String[] args) {
System.out.println("testTreeSetRemove");
Set<String> treeSetStrs = new TreeSet<>();
treeSetStrs.add("aa");
treeSetStrs.add("bb");
treeSetStrs.add("cc");
testSetRemove(treeSetStrs);
System.out.println("testHashSetRemove");
Set<String> shSetStr = new HashSet<>();
shSetStr.add("aa");
shSetStr.add("bb");
shSetStr.add("cc");
testSetRemove(shSetStr);
}
public static void testSetRemove(Set<String> setIn){
try {
setIn.remove("aa");
setIn.remove(null);
} catch (Exception e) {
e.printStackTrace();
}
}
运行上面的代码:会在testSetRemove(treeSetStrs);报错如下 :
java.lang.NullPointerException
at java.util.TreeMap.getEntry(TreeMap.java:347)
at java.util.TreeMap.remove(TreeMap.java:603)
at java.util.TreeSet.remove(TreeSet.java:276)
报错的根据原因在于入参:
1,一个是hashSet;
2, 一个是TreeSet;
在测试方法中我们对于元素的移除,treeSet是不允许为null的。所以才会报错。在我们使用接口入参,在方法里的操作。需要注意在不同的实现中是否允许。
在Java中,`HashSet`和`TreeSet`都是存储不重复元素的集合,但它们在内部数据结构、性能特点以及元素排序方式上有所不同。以下是`HashSet`和`TreeSet`的主要区别:
1. **内部数据结构**:
- `HashSet`:基于`HashMap`实现,使用哈希表来存储元素,因此添加、删除和查找元素的操作平均时间复杂度为O(1)。
- `TreeSet`:基于`NavigableMap`(红黑树)实现,使用平衡二叉树(通常是红黑树)来存储元素,因此元素会处于排序状态。
2. **元素排序**:
- `HashSet`:不保证元素的顺序,元素是无序的。
- `TreeSet`:元素会根据自然排序或提供的`Comparator`进行排序,元素是有序的。
3. **性能特点**:
- `HashSet`:在大多数情况下,`HashSet`的性能更优,特别是在频繁进行添加、删除和查找操作时。
- `TreeSet`:由于需要维护元素的有序性,`TreeSet`在添加和删除元素时可能需要进行树的旋转等操作,因此性能略逊于`HashSet`。
4. **查找性能**:
- `HashSet`:查找元素的时间复杂度为O(1)。
- `TreeSet`:查找元素的时间复杂度为O(log n)。
5. **遍历顺序**:
- `HashSet`:迭代器返回元素的顺序是不确定的,因为元素是随机存储的。
- `TreeSet`:迭代器按照自然排序或定制排序的顺序返回元素。
6. **并发性**:
- `HashSet`和`TreeSet`都不是线程安全的。如果需要在多线程环境中使用,可以考虑使用`Collections.synchronizedSet`包装它们,或者使用`ConcurrentHashMap`作为基础实现自定义线程安全的集合。
7. **使用场景**:
- `HashSet`:适用于对元素顺序没有要求,但需要快速插入、删除和查找的场景。
- `TreeSet`:适用于需要元素有序的场景,例如需要按顺序遍历集合或需要有序输出结果的场景。
总的来说,选择`HashSet`还是`TreeSet`取决于你的具体需求,如果需要快速的查找且不需要元素有序,则`HashSet`是更好的选择;如果需要元素有序,则`TreeSet`更合适。