Skip to content

Latest commit

 

History

History
1312 lines (942 loc) · 34.9 KB

集合.md

File metadata and controls

1312 lines (942 loc) · 34.9 KB

集合

Collection集合

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

Collection:一种装数据的容器,可以存储多个数据

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

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

image-20211124224140094

image-20211124224204072

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); 添加集合

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

集合和数组的区别

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

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

集合:长度可变

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

List集合

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

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

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

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

image-20211124224238912

新特性

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

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

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

ArrayList<E>

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

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

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

集合声明

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

集合添加元素

public boolean add(E e) 返回布尔值,true添加成功
//数组声明时,需要指定长度
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);
}

集合删除元素

根据元素下标删除,返回删除的元素

public E remove(int index)
ArrayList<String> list = new ArrayList<>();
list.add("2");
list.add("3");
list.add("5");
String str = list.remove(0);
System.out.println(str);

获取集合里面的元素

通过下标获取

public E get(int index)
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);

遍历集合

public int size()
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

增强for循环

jdk1.5 可用来遍历集合,数组; 注意:不要在遍历的过程中对集合进行增删操作!!!

内部采用了迭代器

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

迭代器

Iterator<E> iterator()

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

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

image-20211124224325896

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源码学习笔记

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

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

image-20230403213144353

image-20230403213109231

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

image-20230403213741725

image-20230403214039555

image-20230403214050924

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() 从此列表表示的堆栈中弹出一个元素。换句话说,删除并返回此列表的第一个元素。

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

Vetor

  1. 排列有序,可重复

  2. 底层使用数组

  3. 速度快,增删慢

  4. 线程安全,效率低

  5. 容量不够时,自动扩容,比例: 当前容量* 2

Set集合

特点

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

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

相关实现类

HashSet

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

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

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

set遍历

//常用方法 添加 遍历 迭代器
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

//内容不同,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

//对象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

TreeSet

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

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

LinkedHashSet

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

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

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

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,将指定的列表按升序排序。

//自定义类比较,实现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

Comparable,Comparator

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

//使用匿名类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();
    }
}

多条件排序

//排序:日期,班次,制丝线,升序排序
负数:升序,正数:降序
                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

增删改查

//声明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

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(),分别获取键和值

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相结合的集合

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

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

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

LinkedHashedMap

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

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

判断重复字符串

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流常用方法

#当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()));

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

#list分组分别对keyvalue排序
/**
 * 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 来排序