Java常用类库之集合Set

Set集合

与List类似,都是继承自Collection接口

与List不同,Set集合是不包含重复元素的集合。 更正式地说,集合不包含元素对e1和e2 ,使得e1.equals(e2)和最多一个null元素

注意:如果将可变对象用作set元素,则必须非常小心。比如存入Person()对象,有些Set集合中不同的属性会因为数据结构的不同运算出不同的位置,如果属性变化那么位置就不对,导致问题发生。

Set方法与List集合的方法类似,但是没有取数据的操作(get()),需要使用toArray()方法或iterator()读取数据。

1. HashSet

HashSet是Set接口下的常用类,散列存放(HashMap)

  • 不能输入重复元素
HashSet<String> set = new HashSet<>();
set.add("楚汉");
boolean flag1 = set.add("相争");
set.add("刘邦");
set.add("项羽");
boolean flag2 = set.add("相争");
System.out.println(flag1);
System.out.println(flag2);
//true
//false
  • 使用迭代的方法遍历读取
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
    System.out.println(iterator.next());
}
//forEach方法比iterator更方便
for (String s: set) {
    System.out.println(s);
}
// 楚汉
// 刘邦
// 项羽
// 相争

2. TreeSet

采用有序的二叉树存储,内部也是基于TreeMap,方法与HashSet类似

迭代器的快速失败和安全失败:

  • 迭代器迭代时数据被修改,导致遍历的结果是错误的,这就叫失败
  • 快速失败,集合改变,集合长度与迭代器遍历之前认为的长度不同,抛出异常
  • 安全失败:迭代前把集合复制了一份,迭代器迭代的是备份,修改的是原集合,不会出错
  • 有些集合是快速失败,有些集合是安全失败,不特殊描述一般是安全失败

TreeSet的iterator方法返回的迭代器是快速失败的 :如果在创建迭代器之后的任何时间修改集合,除了通过迭代器自己的remove方法之外,迭代器将抛出ConcurrentModificationException 。 因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险。

TreeSet<String> data = new TreeSet<>();
data.add("B");
data.add("A");
data.add("F");
data.add("E");
for (String s:data) {
    System.out.println(s);
}
// A
// B
// E
// F

由上面可见,TreeSet根据字符的Unicode大小进行排序,但是如果遇到对象,含有多个可更改的属性,TreeSet如何排序

TreeSet<Person> data = new TreeSet<>();
Person p1 = new Person("李四", 18);
Person p2 = new Person("张三", 20);

data.add(p1);
data.add(p2);

for (Person  p:
        data) {
    System.out.println(p);
}

static class Person{
    private String name;
    private int age;
}

抛出异常:ClassCastException: class Demo7$Person cannot be cast to class java.lang.Comparable
java.lang.Comparable 接口是用来实现比较大小的,这表明Person类的对象无法比较大小。

解决方法:

  1. Person()类继承Comparable接口,比较对象为Person。
  2. 重写compareTo方法自定义比较的规则
  3. compareTo返回值可以是:负数(this < o),0(this = o),正数(this > o)
static class Person implements Comparable<Person>{
    private String name;
    private int age;

    @Override
    public int compareTo(Person o) {
        //this与o比较
        //返回的可以是:负数(this<o),0(this=o),正数(this>o)
        return this.age-o.age;
    }
}
//输出:
//Person{name='李四', age=18}
// Person{name='张三', age=20}

但是,此时如果加入年纪相同的对象Person p3 = new Person("王五", 18),由于Set集合不会存储相同数据,而通过compareTo发现18岁的人已经存在,所以不会存入。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值