集合还在只用list吗?不如看一下Set集合

java面试题:

throw 和 throws 的区别? (1)throw

作用在方法内,表示抛出具体异常,由方法体内的语句处理; 一定抛出了异常;

(2)throws

作用在方法的声明上,表示抛出异常,由调用者来进行异常处理; 可能出现异常,不一定会发生异常;

1.Set集合

Set集合特点

  • 无序:存取顺序不一致
  • 不重复:可以去重
  • 无索引:没有索引,不能使用for循环遍历

Set实现类

  • HashSet:无序、不重复、无索引
  • LinkedHashSet:有序、不重复、无索引
  • TreeSet:排序、不重复、无索引
        // Set集合特点 HashSet LinkedHashSet TreeSet

        // HashSet 无序,不重复,无索引
        // Set<String> set = new HashSet<>();

        //LinkedHashSet 有序,不重复,无索引
        // Set<String> set = new LinkedHashSet<>();

        //TreeSet 排序,不重复,无索引
        Set<String> set = new TreeSet<>();
        set.add("java");
        set.add("java");
        set.add("mybatis");
        set.add("redis");
        set.add("redis");
        set.add("mysql");
        System.out.println(set);

2.HashSet底层原理

  • HashSet集合底层采用哈希表存储数据
  • 哈希表是一种对增删改查数据性能都比较好的结构

哈希表的组成

  • jdk8之前,底层使用数组+链表组成
  • jdk8之后,底层使用数组+链表+红黑树组成

jdk1.7版本的哈希表实现方法:

  • 创建一个默认长度16的数组
  • 根据元素的哈希值跟数组的长度求余,算出应存入的位置(哈希算法)
  • 判断当前位置是否为null,如果是null直接存入
  • 如果位置不为null,表示有元素,则调用equals方法比较
  • 如果一样,则不存,如果不一样,则存入数组
    • jdk7新元素占老元素位置,指向老元素
    • jdk8中新元素挂在老元素下面
      在这里插入图片描述
      在这里插入图片描述
      jdk1.8版本开始HashSet实现方法:
  • 底层结构:哈希表(数组、链表、红黑树
  • 当挂在元素下面的数据过多时,查询性能降低,从jdk8开始后,当链表长度超过8时候,自动转换为红黑树,进一步提高了操作数据的性能

3.LinkedHashSet集合

LinkedHashSet是HashSet的一个子类,继承了HashSet的一些特性

特点

  • 有序、不重复、无索引
  • 存入顺序与取出顺序一致
  • 原理:底层数据结构还是哈希表,但是每个元素额外多了一个双链表的机制记录存储顺序
    在这里插入图片描述
    底层通过双链表记录添加顺序,所以LinkedHashSet是有序的

3.TreeSet集合

特点

  • 不重复、无索引、可排序
  • 可排序:默认按照元素的从小到大排序
  • TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好
  • TreeSet集合一定要排序,可以将元素按照指定的规则进行排序

默认排序规则

  • 数值类型:Integer、Double,官方默认按照从小到大进行排序
  • 对于字符串类型:默认按照首字符编号升序排序
  • 对于自定义类,TreeSet无法直接排序,需要我们自己制定排序规则

排序实例

        Set<String> set = new TreeSet<>();
        set.add("y");
        set.add("a");
        set.add("Y");
        set.add("A");
        set.add("你好");
        System.out.println(set);

小写字母的ASCII编码要大于大写字母的ASCII编码,汉字的ASCII编码要大于字母的ASCII编码,所以大写字母排在前面,汉字排在后面
在这里插入图片描述
自定义类的排序方法

  • 方法一:
    让自定义类实现comparable接口,重写compareTo方法,制定比较规则

  • 方法二:
    TreeSet集合有参构造函数,可以设置Comparator接口对应的比较器对象,来制定比较规则

自定义排序实例
方法一:
定义一个商品类,实现Comparable接口的comparable方法进行比较。

  • comparable返回1,表示当前对象大于比较对象
  • comparable返回-1,表示当前对象小于比较对象
  • comparable返回0,表示当前两个对象相同

这里的comparable方法不会去重,如果两个对象的价格相等,则规定当前对象大于比较的对象。

public class Produce implements Comparable<Produce>{

    private String id;
    private String name;
    private Double price;

    public Produce() {
    }

    public Produce(String id, String name, Double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Produce produce = (Produce) o;
        return Objects.equals(id, produce.id) && Objects.equals(name, produce.name) && Objects.equals(price, produce.price);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, price);
    }

    @Override
    public String toString() {
        return "Produce{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    /**
     *
     * @param o
     * @return
     */
    @Override
    public int compareTo(Produce o) {
        //根据价格进行比较
        return this.price - o.price >= 0 ? 1 : -1;
    }
}
        Set<Produce> set1 = new TreeSet<>();
        set1.add(new Produce("0001","苹果",5.0));
        set1.add(new Produce("0002","香蕉",3.4));
        set1.add(new Produce("0003","西瓜",1.2));
        set1.add(new Produce("0004","黄瓜",3.4));

        System.out.println(set1);

输出样例
在这里插入图片描述
方法二:
如果类中存在比较器,构造函数中也存在比较器,那么优先使用构造器的比较规则

        Set<Produce> set1 = new TreeSet<>(new Comparator<Produce>() {
            @Override
            public int compare(Produce o1, Produce o2) {
                return o1.getPrice() - o2.getPrice() >= 0 ? 1 : -1;
            }
        });
        set1.add(new Produce("0001","苹果",5.0));
        set1.add(new Produce("0002","香蕉",3.4));
        set1.add(new Produce("0003","西瓜",1.2));
        set1.add(new Produce("0004","黄瓜",3.4));

        System.out.println(set1);

我们还可以通过lambda表达式将代码简写成一行

 Set<Produce> set1 = new TreeSet<>((o1, o2) -> o1.getPrice() - o2.getPrice() >= 0 ? 1 : -1);

如果想要去重,我们可以使用Double包装类中的compare方法进行比较去重。

        Set<Produce> set1 = new TreeSet<>(new Comparator<Produce>() {
            @Override
            public int compare(Produce o1, Produce o2) {
                return Double.compare(o1.getPrice(),o2.getPrice());
            }
        });

总结

  • 如果想要增删改查速度快,但是元素无序,不重复,无索引
    • 使用HashSet
  • 如果想要增删改查速度快,但是元素有序,不重复,无索引
    • 使用LinkedHashSet
  • 如果想要对对象进行排序
    • 使用TreeSet
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狗头实习生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值