---
url: /notes/java-se/集合/index.md
---
# 集合

# Collection集合

<https://github.com/itwanger/toBeBetterJavaer/blob/master/collection/gailan.md>

`Collection`：一种装数据的容器，可以存储多个数据

所有单列接口的顶层接口，定义了所有单列集合的共有方法

任意的单列集合都可以使用Collection接口中的方法

![image-20211124224140094](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224140094.png)

![image-20211124224204072](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224204072.png)

`NavigableMap`可以按升序或降序键顺序访问和遍历

**CopyOnWrite** **ArrayList**

**读写分离：读时共享、写时复制(原本的array)更新(且为独占式的加锁**

1. 每个CopyOnWriteList对象里面有一个array数组来存放具体元素

2. 使用ReentrantLock独占锁来保证只有写线程对array副本进行更新。

3. CopyOnWriteArrayList在遍历的使用不会抛出ConcurrentModificationException异常，并且遍历的时候就不用额外加锁

`Collections.SynchronizedList`

同步代码块实现，迭代器没有加锁

**CopyOnWrite** **ArraySet**

其实CopyOnWriteSet底层包含一个CopyOnWriteList，几乎所有操作都是借助CopyOnWriteList，就像HashSet包含HashMap

1. 它最适合于具有以下特征的应用程序：Set 大小通常保持很小，只读操作远多于可变操作，需要在遍历期间防止线程间的冲突。

2. 它是线程安全的。

3. 因为通常需要复制整个基础数组，所以可变操作（add()、set() 和 remove() 等等）的开销很大。

4. 迭代器支持hasNext(), next()等不可变操作，但不支持可变 remove()等 操作。

5. 使用迭代器进行遍历的速度很快，并且不会与其他线程发生冲突。在构造迭代器时，迭代器依赖于不变的数组快照。

`Collections.SynchronizedList`

**这几个方法没有加锁**

`itearator()，spliterator()，stream()，parallelStream()`

**ConcurrentHashMap**

在内部采用了一个叫做Segment的结构，一个Segment其实就是一个类Hash Table的结构，Segment内部维护了一个链表数组

`Collections.SynchronizedMap`

# 常用方法

`int size();`	获取集合尺寸

`boolean isEmpty();`	判断集合是否为空

`boolean contains(Object o);	`判断集合是否包含指定的对象

`Object[] toArray();`	集合转换数组

`boolean add(E e);	`	追加元素

`boolean remove(Object o);`	删除指定的元素

`void clear();	`			清空集合

`boolean containsAll(Collection<?> c);`

`boolean addAll(Collection<? extends E> c);` 添加集合

```java
Collection<String> list =new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        list.add("eee");
        System.out.println(list);
        ArrayList<String> ls =new ArrayList<>();
        ls.add("dd");
        ls.add("fsf");
        //集合添加集合
        list.addAll(ls);
        System.out.println(list);

        //判断集合是否为空
        System.out.println(list.isEmpty());

        //判断集合是否包含
        System.out.println(list.contains("ccc"));

        //集合转数组
        Object[] obj = list.toArray();
        for (int i = 0; i < obj.length; i++) {
            System.out.print(obj[i]+"\t");
        }
        System.out.println();
        //清空集合
        list.clear();
        System.out.println(list);
```

![image-20211124224225615](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224225615.png)

# 集合和数组的区别

数组：程序运行后，数组的**长度固定** ，添加或者减少元素变得困难

存储的**同一类型** 的元素，可以存储**基本类型值**

集合：**长度可变**

存储的都是**对象类型** ，而且**对象类型可以不一致** ，当开发中存储对象比较多的时候，推荐使用集合

# List集合

继承与Collection接口，存放的是可以**重复的元素**

**List集合** : 底层采用的数据结构**数组**

1. 存入的数据都是**有序** ，**可以重复的元素** ，有序--->存储的顺序和取出来顺序是一致的

2. **有索引的** ，包含一些带索引的方法

![image-20211124224238912](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224238912.png)

## 新特性

`static <E> List<E> of(E e1)`: 生成一个不可变的集合

```java
public class Demo {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("hello");
        list.add("hello");
        list.add("bbb");
        list.add("aaa");
        System.out.println(list);

        //添加元素
        list.add(1,"ccc");
        System.out.println(list);

        //删除元素
        list.remove(0);
        list.remove("aaa");
        System.out.println(list);

        //设置元素
        list.set(0,"aaa");
        System.out.println(list);

        //遍历元素
        Iterator<String> iterator=list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        for (String s : list) {
            System.out.println(s);
        }
        //新特性：不变的集合
        List<String> li = List.of("aaa", "bbb", "ccc", "ddd");
        System.out.println(li);
        li.add("sss"); // UnsupportedOperationException
    }
}
```

![image-20211124224249533](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224249533.png)

```java
public class Demo {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("hello");
        list.add("hello");
        list.add("bbb");
        list.add("aaa");
        System.out.println(list);

        //添加元素
        list.add(1,"ccc");
        System.out.println(list);

        //删除元素
        list.remove(0);
        list.remove("aaa");
        System.out.println(list);

        //设置元素
        list.set(0,"aaa");
        System.out.println(list);

        //遍历元素
        Iterator<String> iterator=list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        for (String s : list) {
            System.out.println(s);
        }
        //新特性：不变的集合
        List<String> li = List.of("aaa", "bbb", "ccc", "ddd");
        System.out.println(li);
        li.add("sss"); // UnsupportedOperationException
        
    }
}
```

## `ArrayList`

1. 排列有序，可重复

2. **底层使用数组**

3. 速度快，增删慢 `get(),set()`

4. **线程不安全**

5. **当容量不够的时候自动扩容 比例:** `当前容量 * 1.5`

![image-20211124224301711](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224301711.png)

`ArrayList<E>`

**泛型** ，通过集合后续给定的类型，知道该集合中只能存储哪些东西

是`java.util.ArrayList`包下面的，底层由**大小可变的数组** 组成，存储的数据称为元素

该类中提供了一些操作元素的方法

### 集合声明

```java
ArrayList<数据类型> 集合名称 = new ArrayList<>();
```

### 集合添加元素

```java
public boolean add(E e) 返回布尔值，true添加成功
```

```java
//数组声明时，需要指定长度
Person[] p1 = new Person[6];
p1[0] = new Person("战士", 23);

//集合声明
// ArrayList<数据类型> 集合名称 = new ArrayList<>();
ArrayList<Person> list = new ArrayList<>();
//集合添加元素
// public boolean add​(E e) 返回布尔值，true添加成功
list.add(new Person("list", 23));

ArrayList<String> peopleNameList = new ArrayList<>();
peopleNameList.add("刘备");
peopleNameList.add("关羽");
peopleNameList.add("张飞");
for (String x : peopleNameList) {
    System.out.println(x);
}

public class Animals {
    private String color;
    private Double weight;

    public Animals(String color, Double weight) {
        this.color = color;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Animals{" +
                "color='" + color + '\'' +
                ", weight='" + weight + "kg" + '\'' +
                '}';
    }
}
ArrayList<Animals> animalsList = new ArrayList<>();
animalsList.add(new Animals("红色", 34.4));
animalsList.add(new Animals("黑色", 20.4));
animalsList.add(new Animals("橘色", 10.2));
for (Animals a : animalsList) {
    System.out.println(a);
}
```

### 集合删除元素

根据**元素下标删除，返回删除的元素**

```java
public E remove(int index)
```

```java
ArrayList<String> list = new ArrayList<>();
list.add("2");
list.add("3");
list.add("5");
String str = list.remove(0);
System.out.println(str);
```

### 获取集合里面的元素

通过下标获取

```java
public E get(int index)
```

```java
ArrayList<String> list=new ArrayList<>();
list.add("5");
list.add("6");
list.add("57");
list.add("8");
String s=list.get(1);
System.out.println(s);
```

### 遍历集合

```java
public int size()
```

```java
ArrayList<String> list=new ArrayList<>();
        list.add("5");
        list.add("6");
        list.add("57");
        list.add("8");

for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}
```

![image-20211124224314845](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224314845.png)

### 增强for循环

`jdk1.5`
可用来遍历集合，数组；
**注意：不要在遍历的过程中对集合进行增删操作！！！**

**内部采用了迭代器**

```java
for(被遍历集合元素类型 变量名称 : 集合的名称){
    //code
}
```

### 迭代器

`Iterator<E> iterator()`

```java
// E next(); 表示下一个元素
// boolean hasNext(); 判断迭代器里面是否有元素
// void remove();

//迭代器遍历
Iterator<Integer> iterator = newNumInter.iterator();
while (iterator.hasNext()) {
    System.out.print(iterator.next() + " ");
}
```

![image-20211124224325896](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224325896.png)

```java
public class Phone {
    private String brand;
    private String color;
    private double price;

    public Phone(String brand, String color, double price) {
        this.brand = brand;
        this.color = color;
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getPrice() {
        return price;
    }

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

    @Override
    public String toString() {
        return "Phone{" +
                "brand='" + brand + '\'' +
                ", color='" + color + '\'' +
                ", price=" + price +
                '}';
    }
}

public class Get {
    public static void main(String[] args) {
        ArrayList<Phone> arrayListPhone=new ArrayList<>();
        arrayListPhone.add(new Phone("苹果","白色",6999));
        arrayListPhone.add(new Phone("华为","黑色",8999));
        arrayListPhone.add(new Phone("小米","蓝色",3999));
        arrayListPhone.add(new Phone("vivo","黄色",1999));
        System.out.println("删除前");
        for (int i = 0; i < arrayListPhone.size(); i++) {
            System.out.println(arrayListPhone.get(i)+"\t");
        }
        for (int i = 0; i < arrayListPhone.size(); i++) {
            Phone p=arrayListPhone.get(i);
            if(p.getBrand().equals("华为")){
                p.setPrice(1);
            }
            if(p.getBrand().equals("vivo")){
                arrayListPhone.remove(i);
            }
        }
        System.out.println("删除后");
        for (int i = 0; i < arrayListPhone.size(); i++) {
            System.out.println(arrayListPhone.get(i)+"\t");
        }
    }
}
```

### ArrayList源码学习笔记

```java
List<Integer> stringList = new ArrayList<>();

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
```

![image-20230403213144353](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note202304032131619.png)

![image-20230403213109231](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note202304032131972.png)

```java
stringList.add(0);

//modCount防止同时操作集合，快速失败
public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }

private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }

private Object[] grow() {
        return grow(size + 1);
    }

//当List为空时，默认最小长度为10，否则扩容大概1.5倍 {>>}
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }

public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
        // assert oldLength >= 0
        // assert minGrowth > 0

        int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
        if (newLength - MAX_ARRAY_LENGTH <= 0) {
            return newLength;
        }
        return hugeLength(oldLength, minGrowth);
    }

//注意长度最大限制
private static int hugeLength(int oldLength, int minGrowth) {
        int minLength = oldLength + minGrowth;
        if (minLength < 0) { // overflow
            throw new OutOfMemoryError("Required array length too large");
        }
        if (minLength <= MAX_ARRAY_LENGTH) {
            return MAX_ARRAY_LENGTH;
        }
        return Integer.MAX_VALUE;
    }
```

![image-20230403213307996](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note202304032133350.png)

![image-20230403213741725](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note202304032137949.png)

![image-20230403214039555](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note202304032140196.png)

![image-20230403214050924](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note202304032140156.png)

```java
stringList.remove(0);

```

## `LinkedList`

1. 排列有序，可重复
2. **底层采用双向循环链表**
3. 查询速度慢，增删快 `add(),remove()`
4. **线程不安全**
5. 离散空间，不需要主动扩容，无扩容机制

由于LinkedList采用了链表，增加了一些对链表的操作：

1. `public void addFirst(E e)`在该列表开头插入指定的元素。

2. `public void addLast(E e)` 将指定的元素追加到此列表的末尾。

3. `public E getFirst()` 返回此列表中的第一个元素。

4. `public E getLast()` 返回此列表中的最后一个元素。

5. `public E peek()` 检索但不删除此列表的头（第一个元素）。

6. `public E poll()`检索并删除此列表的头（第一个元素）。

7. `public void push(E e)` 将元素推送到由此列表表示的堆栈上。换句话说，在该列表的前面插入元素。

8. `public E pop()` 从此列表表示的堆栈中弹出一个元素。换句话说，删除并返回此列表的第一个元素。

```java
package com.datastructure.demo2;

import java.util.LinkedList;

/**
 * @author 涂鏊飞tu_aofei@163.com
 * @description: TODO 类描述
 * @create 2021-08-09 11:09
 */
public class Demo {
    public static void main(String[] args) {
        LinkedList<String> list=new LinkedList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        //在头部添加元素
        list.addFirst("fff");
        System.out.println(list);
        //在尾部添加元素
        list.addLast("ggg");
        System.out.println(list);
        //得到第一个元素
        System.out.println(list.getFirst());
        //得到最后一个元素
        System.out.println(list.getLast());
        //得到头部元素
        System.out.println(list.peek());
        //得到头部第一个元素，并删除
        list.poll();
        System.out.println(list);
        //头部添加元素
        list.push("yyy");
        System.out.println(list);
        //删除第一个元素
        list.pop();
        System.out.println(list);
    }
}
```

![image-20211124224339103](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224339103.png)

## `Vetor`

1. 排列有序，可重复

2. **底层使用数组**

3. **速度快，增删慢**

4. **线程安全，效率低**

5. **容量不够时，自动扩容，比例：** `当前容量* 2`

# Set集合

## 特点

1. 不允许存储重复的元素

2. 没有索引的，没有和索引相关的方法，也不能使用普通的for循环遍历

## 相关实现类

### `HashSet`

存储的元素是**无序的** ，**不可重复的** ，底层使用的是`hash`**表** ，内部采用`hashmap`
**线程不安全**

> HashSet 首先判断两个元素的哈希值，如果哈希值一样，接着会比较 equals 方法 如果 equls 结果为 true ，HashSet 就视为同一个元素。如果 equals 为 false 就不是 同一个元素。

当存储元素的时候会比较内容的hashcode值如果相同会覆盖原来的位置

### set遍历

```java
//常用方法 添加 遍历 迭代器
public class SetDemo {
    public static void main(String[] args){
        Set<String> set=new HashSet<>();

        //添加元素
        set.add("aaa");
        set.add("bbb");
        set.add("ccc");

        //遍历
        for (String s : set) {
            System.out.println(s);
        }
        //迭代器遍历
        Iterator<String> iterator=set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

```

![image-20211124224353834](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224353834.png)

```java
//内容不同，hashcode值相同 先比较hashcode，再比较equals
public class HashSetDemo {
    public static void main(String[] args){
        Set<String> set=new HashSet<>();
        String st1=new String("abc");
        String st2=new String("abc");
        set.add(st1);
        set.add(st2);
        System.out.println(set);

        System.out.println(st1.hashCode());
        System.out.println(st2.hashCode());

        System.out.println("重地".hashCode());
        System.out.println("通话".hashCode());
        set.add("重地");
        set.add("通话");
        System.out.println(set);
    }
}
```

![image-20211124224505161](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224505161.png)

```java
//对象hashcode值不同，内容相同 重写hashcode方法
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

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

public class DemoPerson {
    /*
        要重写person的hashcode方法
     */
    public static void main(String[] args){
        Set<Person> set=new HashSet<>();
        Person p1=new Person("张三",18);
        Person p2=new Person("李四",19);
        set.add(p1);
        set.add(p2);
        System.out.println(set);

        Person p3=new Person("小美女",18);
        Person p4=new Person("小美女",18);
        set.add(p3);
        set.add(p4);
        System.out.println(p3.hashCode());
        System.out.println(p4.hashCode());
        System.out.println(set);
    }

}
```

![image-20211124224515341](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224515341.png)

### `TreeSet`

存储的元素是**无序的** ，**不可重复的** ，底层使用的是**二叉树** ，**排序存储** ，内部采用了`treemap`**的** `sortedset`
**线程不安全**

```java
public class TreeSet {
    public static void main(String[] args) {
        Set<String> set = new TreeSet<>();
        set.add("aaa");
        set.add("bbb");
        set.add("ccc");
        set.add("ddd");
        System.out.println(set);
    }
}
```

![image-20211124224526282](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224526282.png)

### `LinkedHashSet`

采用了`hash`**表** 存储，但是用了**链表来记录存储的数据** ，使得存入数据与取出数据变的有序，内部使用的是`linkedhashmap`
**线程不安全**
**​**

继承于`hashSet`、又基于 `LinkedHashMap `来实现的LinkedHashSet 底层使用 LinkedHashMap 来保存所有元素，它继承与 HashSet，其所有的方法 操作上又与 HashSet 相同

```java
public class LinkedHashSetDemo {
    public static void main(String[] args) {
        HashSet<String> st1=new HashSet<>();
        st1.add("w22");
        st1.add("bbb");
        st1.add("ccc");
        System.out.println(st1);

        LinkedHashSet<String> st2=new LinkedHashSet<>();
        st2.add("w22");
        st2.add("bbb");
        st2.add("ccc");
        System.out.println(st2);
    }
}
```

![image-20211124224536548](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224536548.png)

# Collections集合工具类

`public static <T> boolean addAll(Collection<? super T> c,T... elements)`

往集合中添加元素

`public static void shuffle(List<?> list)`

使用默认的随机源随机排列指定的列表。 所有排列都以大致相等的可能性发生。

`public static <T extends Comparable<? super T>> void sort(List<T> list)`

根据其元素的[natural ordering](../../java/lang/Comparable.html)，将指定的列表按升序排序。

```java
//自定义类比较，实现Comparable接口，重写compareTo方法
public class Person implements Comparable<Person> {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    /**
     * description: TODO
     *
     * @since: 1.0.0
     * @author: 涂鏊飞tuao_fei@163.com
     * @date: 2021/8/10 10:38
     * @Param o:
     * @return: int
     * 0表示两个元素相等
     * 负值：降序
     * 正值：升序
     */
    @Override
    public int compareTo(Person o) {
//        return this.getAge() - o.getAge();
        return o.getAge() - this.getAge();
    }
}

public class DemoPerson {
    public static void main(String[] args) {
        List<Person> list=new ArrayList<>();
        list.add(new Person("张三",18));
        list.add(new Person("李四",17));
        list.add(new Person("王五",15));
        System.out.println(list);

        Collections.sort(list);
        System.out.println(list);
    }
}
```

![image-20211124224548831](https://note-1259190304.cos.ap-chengdu.myqcloud.com/note/image-20211124224548831.png)

## `Comparable,Comparator`

Integer 和 String 对象都可以进行默认的 TreeSet 排序，而自定义类的对象是不可以的，**自己定义的类必须实现 Comparable 接口** ，并且覆写相应的 `compareTo()`函数，才可以正常使用。
如果该对象小于、等于或大于指定对象，则分别返回负整数、零或正整数。

```java
//使用匿名类Comparator
public class Athletes /*implements Comparable<Athletes>*/{

    private String name;
    private int zj;
    private int jt;
    private int sumScore;

    public String getName() {
        return name;
    }

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

    public int getZj() {
        return zj;
    }

    public void setZj(int zj) {
        this.zj = zj;
    }

    public int getJt() {
        return jt;
    }

    public void setJt(int jt) {
        this.jt = jt;
    }

    public int getSumScore() {
        return sumScore;
    }


    public Athletes(String name, int zj, int jt) {
        this.name = name;
        this.zj = zj;
        this.jt = jt;
        this.sumScore = zj + jt;
    }

    @Override
    public String toString() {
        return "Athletes{" +
                "name='" + name + '\'' +
                ", zj=" + zj +
                ", jt=" + jt +
                ", sumScore=" + sumScore +
                '}';
    }

//    @Override
//    public int compareTo(Athletes o) {
//        return this.getSumScore()-o.getSumScore();
//    }
}
public class Test3 {
    public static void main(String[] args) {
        LinkedList<Athletes> list=new LinkedList<>();
        Collections.addAll(list,
                new Athletes("颤三",125,264),
                new Athletes("李四",251,251),
                new Athletes("王五",235,240)
        );
        System.out.println(getMax(list));

    }
    public static Athletes getMax(LinkedList<Athletes> list){
//        Collections.sort(list);
        Collections.sort(list, new Comparator<Athletes>() {
            @Override
            public int compare(Athletes o1, Athletes o2) {
                return o1.getSumScore()-o2.getSumScore();
            }
        });
        System.out.println(list);
        return list.getLast();
    }
}
```

多条件排序

```java
//排序：日期，班次，制丝线，升序排序
负数：升序，正数：降序
                if (WsdCollectionUtils.isNotEmpty(res)) {
                    Collections.sort(res, (o1, o2) -> {
                        String workDate1 = o1.getWorkDate();
                        String workDate2 = o2.getWorkDate();
                        int i1 = workDate1.compareTo(workDate2);

                        String classLabel1 = o1.getClassLabel();
                        String classLabel2 = o2.getClassLabel();
                        int i2 = classLabel1.compareTo(classLabel2);

                        String lineCode1 = o1.getLineCode();
                        String lineCode2 = o2.getLineCode();
                        int i3 = lineCode1.compareTo(lineCode2);

                        if (i1 == 0) {
                            if (i2 == 0) {
                                return i3;
                            }
                            return i2;
                        }
                        return i1;
                    });
                }
```

# map集合

`Map<k,v>`

## 特点

1. Map集合是一个**双列集合** ，一个元素包含两个值k,v

2. Map集合中的元素，key和value的数据类型可以相同也可以不同

3. Map集合中的元素，**key不能重复** ，**value可以重复**

4. Map集合中的元素，key和value是一一对应的

## Map接口的实现类

### `hashmap`

底层使用了`hash`**表** ，查询速度特别快
JDK1.8以前使用`hash表+链表`
JDK1.8以后使用**hash表+链表** （**红黑树** ：当链表长度超过**8** 时）
**线程不安全** ，key和value**都可以存储** `null`**值**

#### 增删改查

```java
//声明Map
        Map<String,String> map=new HashMap<>();
        Map<Person,Integer> map1=new HashMap<>();
        //添加
        map.put("41151","张三");
    map.put("41151","李四"); // 相当于修改，会覆盖原来的位置
        map1.put(new Person(),25);

// V remove(Object key) 删除元素
        String s = map.remove("郭靖");
        System.out.println(s);

// V get(Object key) 通过集合中的key值，获取对应的value
        String value = map.get("郭靖");
        System.out.println(value);

// 判断是否包含对应的键和值
        boolean b = map.containsKey("杨过");
        System.out.println(b);
        boolean b1 = map.containsValue("小龙女");
        System.out.println(b1);
```

#### map遍历

1. **通过键找值**

`Set<K> KeySet()` 通过该方法返回映射中所有键的set视图

1. 通过使用map集合中KeySet方法，把map集合中的所有key值获取，存到set集合中

2. 遍历set集合，获取map集合中的每一个key

3. 通过map集合中的get(key)，通过key找到value

```java
Map<String, Integer> map = new HashMap<>();
        map.put("武汉", 18);
        map.put("武汉", 20);
        System.out.println(map);

        map.put("南京", 50);
        map.put("扬州", 50);
        System.out.println(map);
        // 获取key值
        Set<String> keySet = map.keySet();
        for (String s : keySet) {
            //根据get得到value
            Integer value=map.get(s);
            System.out.println("key:"+s+",value:"+value);
        }
        //简化写法
        for (String s : map.keySet()) {
            System.out.println("key:"+s+",value:"+map.get(s));
        }
```

1. 使用Map集合中的`Set<Map.Entry<K,V>> entrySet();` 返回此映射中包含的映射关系的set视图

2. 使用Map集合中的方法entrySet()，把Map集合中的多个entry对象取出来，存到set集合中

3. 遍历set集合，获取每一个Entry对象

4. 使用Entry对象中的方法getKey()和getValue()，分别获取键和值

```java
Set<Map.Entry<String, Integer>> entries = map.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            String key=entry.getKey();
            Integer value=entry.getValue();
            System.out.println("key:"+key+",value:"+value);
        }
```

### `hashTable`

**线程安全** ，key和value**不可以存储null值**
存放的是无序不可重复的键值对

JDK1.2以后被hashmap替换，有一个子类`Properties`依然在使用
`Properties对象是唯一一个集合和IO相结合的集合`

```java
Map<String,Integer> map=new Hashtable<>();
        map.put("站撒",13);
        map.put("李四",14);
        map.put("网袜",15);
//        map.put(null,null); Hashtable中key和value都不能为null
        System.out.println(map);

        Map<String,Boolean> map1=new HashMap<>();
        map1.put(null,null);
```

### `treemap`

底层使用**二叉树** **线程不安全**

```java
Map<String,Integer> map=new TreeMap<>();
        map.put("张三",18);
        map.put("李四",25);
        System.out.println(map);
```

### `LinkedHashedMap`

底层采用`hash表+链表`
保存了记录的插入顺序
**线程不安全**

```java
LinkedHashMap<String,Integer> map=new LinkedHashMap<>();
        map.put("张三",26);
        map.put("前进",65);
        map.put("后退",56);
        System.out.println(map);
```

### 判断重复字符串

```java
System.out.println("请输入字符串：");
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();
        Map<Character, Integer> map = new HashMap<>();
        for (char c : str.toCharArray()) {
            //如果包含键c
            if (map.containsKey(c)) {
                //拿到键对应的值
                Integer value = map.get(c);
                // ++
                value++;
                // 覆盖
                map.put(c,value);
            } else {
                //没有出现过，初始值1
                map.put(c, 1);
            }
        }
        for (Character character : map.keySet()) {
            System.out.println("key："+character+"，value："+map.get(character));
        }
```

### stream流常用方法

```java
#当key相同时，去前或者后面的一位
list.stream().collect(Collectors.toMap(item -> item.getXXX(), item -> item, (oldVal, newVal) -> newVal));

#某个属性累加
list.stream().map(Object::getXXX).reduce(BigDecimal.ZERO, BigDecimal::add);

#最小的值
list.stream().min(Comparator.comparing(Object::getXXX)).get();

#最大的值
list.stream().max(Comparator.comparing(Object::getXXX)).get();

#list分组对value排序
TreeMap<String, List<Object>> map = list.stream().collect(Collectors.groupingBy(item -> WsdDateUtils.dateToStr(item.getXXX(), "yyyy-MM-dd"), TreeMap::new, Collectors.toList()));

#对map的value排序
ArrayList<Map.Entry<String, Integer>> entries = new ArrayList<>(defectMap.entrySet());
Collections.sort(entries, Comparator.comparing(Map.Entry::getValue));

#list分组分别对key和value排序
/**
 * Map通过key进行排序
 * @param map
 * @param isDesc
 * @param <K>
 * @param <V>
 * @return
 */
public static <K extends Comparable<? super K>, V> Map<K, V> sortByKey(Map<K, V> map, boolean isDesc) {
    Map<K, V> result = new LinkedHashMap<>();
    if (isDesc) {
        map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByKey().reversed())
                .forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
    } else {
        map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByKey())
                .forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
    }
    return result;
}
把 "map.entrySet().stream().sorted(Map.Entry.<K, V>comparingByKey().reversed())" 里面的
comparingByKey()换成comparingByValue() 就是根据 value 来排序 
```
