Java集合详解(List和Set)

简介: Java集合讲解!入门学习!

一. 集合的诞生

集合是为了弥补数组的不足而存在。

集合相对于数组优势在于:a.集合的长度可以动态改变;b.集合中能够存放多种类型的数据。

在这里插入图片描述

二. 集合的家族

Collection接口是所有单值集合的父接口

List接口与Set接口的区别:

在这里插入图片描述

一个集合类的对象就一个集合。

Collection中常用的方法

方法名 描述
add(E e) 确保此 collection 包含指定的元素(可选操作)。
clear() 移除此 collection 中的所有元素(可选操作)。
contains(Object o) 如果此 collection 包含指定的元素,则返回true
equals(Object o) 比较此 collection 与指定对象是否相等
isEmpty() 如果此 collection 不包含元素,则返回true。
iterator() 返回在此 collection 的元素上进行迭代的迭代器。
remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话。
size() 返回此 collection 中的元素数。
toArray() 返回包含此 collection 中所有元素的数组。

1、List集合有序,可重复)

ArrayList:LinkedList:

①ArrayList: 底层数据结构是数组,查询快,增删慢

②LinkedList: 底层数据结构是链表,查询慢,增删快

两者共同缺点: 线程不安全,效率高


Vector:

①优点: 底层数据结构是数组,查询快,增删慢。

②缺点: 线程安全,效率低

小结:底层数据结构特点决定其性能特性

---

2、Set集合—(无序,唯一)

  • Set接口是Collection的子接口,表示元素无序且不可重复的集合。

在这里插入图片描述
(1)HashSet:

底层数据结构是哈希表。(无序,唯一)

如何来保证元素唯一性?

1、依赖两个方法:hashCode()和equals()
2、HashSet底层数据结构采用哈希表实现,元素无序且唯一,线程不安全,效率高,可以存储null元素,元素的唯一性是靠所存储元素类型是否重写hashCode()和equals()方法来保证的,如果没有重写这两个方法,则无法保证元素的唯一性。


具体实现唯一性的比较过程:

1.存储元素时首先会使用hash()算法函数生成一个int类型hashCode散列值,然后已经的所存储的元素的hashCode值比较,如果hashCode不相等,肯定是不同的对象。
2.hashCode值相同,再比较equals方法。
3.equals相同,对象相同。(则无需储存)


(2)LinkedHashSet:

底层数据结构是链表和哈希表 (FIFO插入有序,唯一)
1.由链表保证元素有序
2.由哈希表保证元素唯一
LinkedHashSet底层数据结构采用链表和哈希表共同实现,链表保证了元素的顺序与存储顺序一致,哈希表保证了元素的唯一性。线程不安全,效率高。


(3)TreeSet:

底层数据结构是红黑树。(唯一,有序)

如何保证元素排序的呢?

1、自然排序

2、比较器排序


如何保证元素唯一性的呢?

1、根据比较的返回值是否是0来决定

2、TreeSet底层数据结构采用红黑树来实现,元素唯一且已经排好序;唯一性同样需要重写hashCode和equals()方法,二叉树结构保证了元素的有序性。根据构造方法不同,分为自然排序(无参构造)和比较器排序(有参构造)

3、自然排序要求元素必须实现Compareable接口,并重写里面的compareTo()方法,元素通过比较返回的int值来判断排序序列,返回0说明两个对象相同,不需要存储;

4、比较器排序要在TreeSet初始化是时候传入一个实现Comparator接口的比较器对象,或者采用匿名内部类的方式new一个Comparator对象,重写里面的compare()方法;


TreeSet实践案例

①在元素类中定义排序规则

import java.util.TreeSet;

//创建学生类实践
public class Student implements Comparable<Student> {
    private String stuNum;
    private String stuName;
    private String stuSex;
    private int stuAge;

    public Student(String stuNum, String stuName, String stuSex, int stuAge) {
        this.stuNum = stuNum;
        this.stuName = stuName;
        this.stuSex = stuSex;
        this.stuAge = stuAge;
    }

    public String getStuNum() {
        return stuNum;
    }

    public void setStuNum(String stuNum) {
        this.stuNum = stuNum;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    public String getStuSex() {
        return stuSex;
    }

    public void setStuSex(String stuSex) {
        this.stuSex = stuSex;
    }

    public int getStuAge() {
        return stuAge;
    }

    public void setStuAge(int stuAge) {
        this.stuAge = stuAge;
    }

    @Override
    public String toString() {
        return "Student{" +
                "编号'" + stuNum + '\'' +
                ", 姓名='" + stuName + '\'' +
                ", 性别='" + stuSex + '\'' +
                ", 年龄=" + stuAge +
                '}';
    }

        //重写里面的compareTo()方法
    @Override
    public int compareTo(Student o) {
        // compareTo 的参数o表示集合中已经存在的元素
        return this.stuAge - o.stuAge;
    }

    //案例
    public static void main(String[] args) {
        //TreeSet<Student> ts = new TreeSet<Student>();

        TreeSet<Student> ts =new TreeSet<Student>();
        Student s1 = new Student("10001", "Lilei", "M", 20);
        Student s2 = new Student("10002", "HanMeimei", "F", 19);
        Student s3 = new Student("10003", "Lily", "F", 21);
        Student s4 = new Student("10004", "Tom", "M", 22);
        ts.add(s1);    // [s1]
        ts.add(s2); // [s2,s1]
        ts.add(s3); // [s2,s1,s3]
        ts.add(s4); // [s2,s1,s3,s4]
        System.out.println(ts);
    }
}

  • 比较器中我们按年龄排序,输出结果也是按年龄排序
[Student{编号'10002', 姓名='HanMeimei', 性别='F', 年龄=19}, 
Student{编号'10001', 姓名='Lilei', 性别='M', 年龄=20},
 Student{编号'10003', 姓名='Lily', 性别='F', 年龄=21},
  Student{编号'10004', 姓名='Tom', 性别='M', 年龄=22}]

给TreeSet集合指定比较器(未继承接口)

import java.util.Comparator;
import java.util.TreeSet;

public class Student {
    private String stuNum;
    private String stuName;
    private String stuSex;
    private int stuAge;

    public Student(String stuNum, String stuName, String stuSex, int stuAge) {
        this.stuNum = stuNum;
        this.stuName = stuName;
        this.stuSex = stuSex;
        this.stuAge = stuAge;
    }

    public String getStuNum() {
        return stuNum;
    }

    public void setStuNum(String stuNum) {
        this.stuNum = stuNum;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    public String getStuSex() {
        return stuSex;
    }

    public void setStuSex(String stuSex) {
        this.stuSex = stuSex;
    }

    public int getStuAge() {
        return stuAge;
    }

    public void setStuAge(int stuAge) {
        this.stuAge = stuAge;
    }

    @Override
    public String toString() {
        return "Student{" +
                "编号'" + stuNum + '\'' +
                ", 姓名='" + stuName + '\'' +
                ", 性别='" + stuSex + '\'' +
                ", 年龄=" + stuAge +
                '}';
    }

    //案例
    public static void main(String[] args) {

        //切记这里是Comparator
        Comparator<Student> cptr = new Comparator<Student>() {
            //o1表示向集合中新增的元素,o2表示集合中已经存在的元素
            public int compare(Student o1, Student o2) {
                int i = o1.getStuAge() - o2.getStuAge();
                return i;
            }
        };
        
        TreeSet<Student> ts = new TreeSet<Student>(cptr);
        Student s1 = new Student("10001", "Lilei", "M", 20);
        Student s2 = new Student("10002", "HanMeimei", "F", 19);
        Student s3 = new Student("10003", "Lily", "F", 21);
        Student s4 = new Student("10004", "Tom", "M", 22);
        ts.add(s1);    // [s1]
        ts.add(s2); // [s2,s1]
        ts.add(s3); // [s2,s1,s3]
        ts.add(s4); // [s2,s1,s3,s4]
        System.out.println(ts);
    }
}

  • 输出结果
[Student{编号'10002', 姓名='HanMeimei', 性别='F', 年龄=19}, 
Student{编号'10001', 姓名='Lilei', 性别='M', 年龄=20},
 Student{编号'10003', 姓名='Lily', 性别='F', 年龄=21},
  Student{编号'10004', 姓名='Tom', 性别='M', 年龄=22}]

注意:小编我在编辑过程将上例中Comparator打错成Comparable导致自定义程序无法出结果,希望大家用比较器也多注意。


补充:Comparable和Comparator区别

  • 对于Comparable接口来说,被比较对象所属的类需要直接实现Comparable接口,实现该接口的类被赋予一个自然顺序,而且该自然顺序只有一个,而Comparator是一个比较器接口,被比较对象所属的类不需要直接实现该接口,可以单独写一个比较器类实现该接口,作为比较对象的一个比较器,对于一个类来说,可以实现多个比较器。
  • Comparator可以选择对null进行比较,而Comparable不可以。主要是因为Comparator的比较对象都是compare方法的参数,而Comparable的比较方法compareTo方法需要对象来调用,而对象为null时(null.compareTo(obj)),会出现异常。

Lambda表达式

是JDK1.8新增的表达式语法,实际上就是一个语法糖,用于对接口中的方法进行实现。

代码修改对比

        //切记这里是Comparator
        Comparator<Student> cptr = new Comparator<Student>() {
            //o1表示向集合中新增的元素,o2表示集合中已经存在的元素
            public int compare(Student o1, Student o2) {
                int i = o1.getStuAge() - o2.getStuAge();
                return i;
            }
        };
        TreeSet<Student> ts = new TreeSet<Student>(cptr);

Lambda表达式的应用

 //Lambda表达式
        TreeSet<Student> ts2 = new TreeSet<Student>((o1,o2)->o1.getStuAge()-o2.getStuAge());

输出结果一样,但是格式更加简洁


May you find the work you are willing to devote to and love it.

非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤️ 分享👥 留言💬thanks!!!

愿你们奔赴在自己的热爱里!

目录
相关文章
|
3天前
|
存储 Java 容器
Java一分钟之-高级集合框架:LinkedList与TreeSet
【5月更文挑战第17天】这篇博客对比了Java集合框架中的LinkedList和TreeSet。LinkedList是双向链表,适合中间插入删除,但遍历效率低且占用空间大;TreeSet基于红黑树,保证元素有序且不重复,插入删除速度较LinkedList慢但查找快。选择时需根据操作需求和性能考虑。
12 2
|
1天前
|
安全 Java 容器
Java一分钟之-并发编程:线程安全的集合类
【5月更文挑战第19天】Java提供线程安全集合类以解决并发环境中的数据一致性问题。例如,Vector是线程安全但效率低;可以使用Collections.synchronizedXxx将ArrayList或HashMap同步;ConcurrentHashMap是高效线程安全的映射;CopyOnWriteArrayList和CopyOnWriteArraySet适合读多写少场景;LinkedBlockingQueue是生产者-消费者模型中的线程安全队列。注意,过度同步可能影响性能,应尽量减少共享状态并利用并发工具类。
15 2
|
1天前
|
Python
两个list集合合并成一个python教程 - 蓝易云
在这两种方法中,加号会创建一个新的列表,而extend方法则会在原地修改列表。
5 0
|
2天前
|
安全 Java 容器
Java一分钟之-高级集合框架:并发集合(Collections.synchronizedXXX)
【5月更文挑战第18天】Java集合框架的`Collections.synchronizedXXX`方法可将普通集合转为线程安全,但使用时需注意常见问题和易错点。错误的同步范围(仅同步单个操作而非迭代)可能导致并发修改异常;错误地同步整个集合类可能引起死锁;并发遍历和修改集合需使用`Iterator`避免`ConcurrentModificationException`。示例代码展示了正确使用同步集合的方法。在复杂并发场景下,推荐使用`java.util.concurrent`包中的并发集合以提高性能。
15 3
|
2天前
|
Java 开发者
Java一分钟之-高级集合框架:优先队列(PriorityQueue)
【5月更文挑战第18天】`PriorityQueue`是Java集合框架中的无界优先队列,基于堆数据结构实现,保证队头元素总是最小。常见操作包括`add(E e)`、`offer(E e)`、`poll()`和`peek()`。元素排序遵循自然排序或自定义`Comparator`。常见问题包括错误的排序逻辑、可变对象排序属性修改和混淆`poll()`与`peek()`。示例展示了自然排序和使用`Comparator`的排序方式。正确理解和使用`PriorityQueue`能提升应用性能。
34 6
|
2天前
|
存储 Java
Java一分钟之-高级集合框架:Queue与Deque接口
【5月更文挑战第18天】本文探讨Java集合框架中的`Queue`和`Deque`接口,两者都是元素序列的数据结构。`Queue`遵循FIFO原则,主要操作有`add/remove/element/peek`,空队列操作会抛出`NoSuchElementException`。`Deque`扩展`Queue`,支持首尾插入删除,同样需注意空`Deque`操作。理解并正确使用这两个接口,结合具体需求选择合适数据结构,能提升代码效率和可维护性。
26 4
|
4天前
|
存储 算法 Java
Java 集合框架
5月更文挑战第10天
|
Java Apache
Java 中 List 分片的 5 种方法!(5)
Java 中 List 分片的 5 种方法!(5)
253 0
Java 中 List 分片的 5 种方法!(5)
|
Java
Java 中 List 分片的 5 种方法!(4)
Java 中 List 分片的 5 种方法!(4)
376 0
Java 中 List 分片的 5 种方法!(4)
|
Java
Java 中 List 分片的 5 种方法!(3)
Java 中 List 分片的 5 种方法!(3)
511 0
Java 中 List 分片的 5 种方法!(3)