一条龙服务玩游戏闯关搞定Java集合

文章目录

一、写在前面的废话

那一年,我大三她大二在月黑风高夜,灯灭人静时,她这学期刚学数据结构大一刚学完Java,但是现在要学数据结构,追着我问:学数据结构有啥用吗

在学习数据结构的时候,问过自己,为什么要学习数据结构吗?
你学完之后可能会发现学了之后啥也干不了。

如果你知道了java中有自带的List、Map、Set等,你学了数据结构之后也会发现,学了数据结构之后也没啥用。

你知道:数据结构+算法=程序吗?

你在开发的时候,如果不懂数据结构的话,当然了也可以开发项目,但是到最后肯定会一团糟。

就像没学过软件工程,直接去开发软件一样。最后一定一定不是一个完美的软件。

因为我是网络工程专业的,听的最多的就是进化史了,像2G到3G,3G到4G,4G到5G。有4G已经很快了为什么要出现5G呢?我在这就不卖关子了,大家可以去网上搜一下。

再换个问题,有http了,为什么还要https?可以去查一查。

如果你思考了上面这两个问题也许就知道,已经有了List、Set、Map为什么还要学数据结构?

下面就让咱们站在巨人的肩膀上学习集合,看看巨人是如何画的一幅幅优美的画

二、集合的概述

(一)她问我集合是什么?

集合:Java提供了集合类集合类主要负责保存、装其他数据,因此集合类也被称为容器类。容器就像杯子装水一样,都是存放东西的。

(二)她又问我,那数组也可以分为不同类型的数组,集合有什么分类呢?

看网上什么类型的图都有,感觉乱七八糟的,也不太适合初学者,下面我画了一个更适合咱们的图

1、Java集合的两大体系

Java集合主要由两大体系构成,分别是Collection体系和Map体系,其中Collection和Map分别是两大体系中的顶层接口。

在这里插入图片描述

2、Collection体系

Collection主要有三个子接口,分别为List(列表)、Set(集)、Queue(队列)。
其中,List、Queue中的元素有序可重复,而Set中的元素无序不可重复

List中主要有ArrayListLinkedList两个实现类;
Set中则是有HashSet实现类;
Queue是在JDK1.5后才出现的新集合,主要以数组链表两种形式存在。

在这里插入图片描述

3、Map体系

Map也是集合的一部分,但与Collection是相互独立的,没有任何关系。
Map中都是以key-value的形式存在,其中key必须唯一;
主要有HashMapHashTableTreeMap三个实现类。

在这里插入图片描述

(三)那集合与数组有哪些区别?【面试经常遇到】

提到容器,就会想起数组,那么集合和数组的区别是什么呢?

  • 1、数组集合都是Java中的容器;
  • 2、数组的长度是固定的,集合的长度是可变的;
  • 3、数组即可以保存基本类型的值,也可以保存对象;
  • 4、集合只能保存对象。

1、带女朋友做个集合与数组的实验,验证一下不同(我女朋友都能看懂,你肯定能看懂)

为了更好的记忆,咱们来验证下

(1)验证第1条:数组和集合都是Java中的容器;

数组存储

int[] intArr = {1,2,3,4};//有局限性,很少使用,测试的时候比较常用,因为数据的长度是不可能变化的,数据必须是知道的
String[] strArr = new String[3];//数据的长度必须是3个
strArr[0] = "a";
strArr[1] = "b";
strArr[2] = "c";

拿List来说:List存储数据

List<String> list = new ArrayList<>();
list.add("a");
list.add("c");
list.add("d");

(2)验证第2条:数组的长度是固定的,集合的长度是可变的;

如果你多放一个数据肯定会报错

String[] strArr = new String[3];//数据的长度必须是3个
strArr[0] = "a";
strArr[1] = "b";
strArr[2] = "c";
strArr[3] = "d";

在这里插入图片描述

拿List来说:而List集合是不会出现越界的
理论上是可以存放无限大小的,大家可以自行百度了解一下,应该是和电脑的内存有关系的。

List<String> list = new ArrayList<>();
list.add("a");
list.add("c");
list.add("d");
list.add("e");

(3)验证第3条:数组即可以保存基本类型的值,也可以保存对象;

//数组保存:基本类型
int[] ints1 = new int[2];
ints1[0] = 1;
//数组保存:对象
Integer [] ints2 = new Integer[2];
ints2[0] = 2;//这个会牵扯到一个拆箱和装箱的过程
//数组保存:对象
Student [] st = new Student[3];
st[0] = new Student("小明");

(4)验证第4条:集合只能保存对象。

在这里插入图片描述
在这里插入图片描述

List<Integer> list1 = new ArrayList<>();
list1.add(1);

List<Student> students = new ArrayList<>();
students.add(new Student("小明"));
students.add(new Student("小红"));

2、参考【死磕Java之Java数据类型的来龙去脉】

如果你到了第3、4步卡住了,不知道int和包装类Integer的区别,请移步:
死磕Java之Java数据类型的来龙去脉
https://blog.csdn.net/qq_17623363/article/details/104914159

三、又跑来说,给我讲讲集合的用法吧

(1)第一滴血 firstblood(拿下数组)

我觉你如果想了解集合,就必须先了解数组,熟悉数组也是非常重要的一个过程,才能大彻大悟。

把题目放这里,就不多说了,大家自行百度吧,有很多好文章在等着你。这里主要说明集合。

在这里插入图片描述

(2)双杀 Double kill(消灭敌人:List之ArrayList)

如何来消灭掉List?
很简单,砸了电脑,从此再也不愁了。

哈哈

回到正轨,继续撤

Collection中List集合是有序的如果面试问到,可别回答不上来
这里的有序,并不是排序的有序,而是针对每个元素插入的位置的顺序是有序的。

如果你点开过ArrayList的源码,则会发现它的存储方式是数组,则是有序的。

看到源代码,别害怕哦,咱们只简单的提一提比较重要的点

transient Object[] elementData; // non-private to simplify nested class access

没有艺术细胞,但是还是想手画,比较快,大家凑活着看:
在这里插入图片描述
1、增加数据
例如:我创建了一个List集合

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

存入1至10个数字;
没错,add()就是增加数据的方法
这里存入的是泛型,你在创建的时候List<Integer> list就已经指定好了泛型。

list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
list.add(8);
list.add(9);
list.add(10);

简单的看一下List.add()的源代码

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

可以看到每次插入的都是elementData[]中,利用size变量控制插入的位置
你肯定好奇,我明明没有给这个数组大小,为什么可以存入数据?而且长度是可变的?
先在这买个官司,暂且不追究扩容机制。

你只需要知道ArrayList的默认长度是10,到了一定的长度就会进行扩容,可以持续关注我,之后会特意出一篇,这里咱们主要介绍用法。

/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;

重新来看增加数据
在这里插入图片描述
add(String e):直接新增数据,默认会在size++的位置加,就是继续追加数据
add(int index,String element):在某一个位置上插入数据
addAlll(Collection<? extends String> c):默认当前的数据的长度的位置追加另一个list的数据
addAlll(int index,Collection<? extends String> c):在指定的位置追加另一个list的数据

测试
add(String e):直接新增数据,默认会在size++的位置加,就是继续追加数据

        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        System.out.println(list.toString());

结果

[a, b, c]

add(int index,String element):在某一个位置上插入数据

        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        System.out.println(list.toString());

        list.add(1,"这是在第1个位置上插入的");
        System.out.println(list.toString());

结果

[a, b, c]
[a, 这是在第1个位置上插入的, b, c]

addAlll(Collection<? extends String> c):默认当前的数据的长度的位置追加另一个list的数据

        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");

        List<String> list2 = new ArrayList<>();
        list2.add("d");

        list.addAll(list2);
        System.out.println(list.toString());

结果

[a, b, c, d]

addAlll(int index,Collection<? extends String> c):在指定的位置追加另一个list的数据

        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");

        List<String> list2 = new ArrayList<>();
        list2.add("d");

        list.addAll(1,list2);
        System.out.println(list.toString());

结果

[a, d, b, c]

== 移除(删除)数据==
可以看出一共有这么几种:
remove(Object o):根据数据删除
remove(int index):根据位置删除
removeAll(Collection<?> c):删除包含某个List的所有的数
remove(Predicate<? super E> filter):通过过滤删除,如果包含,就删除
在这里插入图片描述

remove(Object o):根据数据删除

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
//查看未移除时的数
System.out.println("查看未移除时的数据:"+list.toString());
//移除数据为b的
list.remove("b");
System.out.println("查看现在的数据:"+list.toString());

结果:

查看未移除时的数据:[a, b, c]
查看现在的数据:[a, c]

remove(int index):根据位置删除

//移除坐标为1的
list.remove(1);
System.out.println("查看现在的数据:"+list.toString());

结果:

查看现在的数据:[a]

removeAll(Collection<?> c):删除包含某个List的所有的数

List<String> list1 = new ArrayList<>();
list1.add("a");
list1.add("b");

List<String> list2 = new ArrayList<>();
list2.add("a");
list2.add("b");
list2.add("c");

//从list2中移除包含list1中所有的元素
list2.removeAll(list1);
System.out.println("查看现在list1的数据:"+list1.toString());
System.out.println("查看现在list2的数据:"+list2.toString());

结果:

查看现在list1的数据:[a, b]
查看现在list2的数据:[c]

remove(Predicate<? super E> filter):通过过滤删除,如果包含,就删除

List<String> list3 =new ArrayList<String>();
list3.add("1");
list3.add("12");
list3.add("13");
list3.add("0");
System.out.println("初始时:"+ list3.toString());
list3.removeIf(s -> s.contains("1"));//对集合进行过滤,删除集合中包含"1"的元素
System.out.println("过滤完:" + list3.toString());

结果:

初始时:[1, 12, 13, 0]
过滤完:[0]

(3)三杀 Triple kill (消灭敌人:List之LinkedList)

LinkedList是一个双向链表,每一个节点都拥有指向前后节点的引用。相比于ArrayList来说,LinkedList的随机访问效率更低。

先看下数据结构(画的不好,正在练,不要打俺,俺老师说了:知错就是好孩子。)
在这里插入图片描述

它继承AbstractSequentialList,实现了List, Deque, Cloneable, Serializable接口。

  • (1)LinkedList实现List,得到了List集合框架基础功能;
  • (2)LinkedList实现Deque,Deque 是一个双向队列,也就是既可以先入先出,又可以先入后出,说简单些就是既可以在头部添加元素,也可以在尾部添加元素;
  • (3)LinkedList实现Cloneable,得到了clone()方法,可以实现克隆功能;
  • (4)LinkedList实现Serializable,表示可以被序列化,通过序列化去传输,典型的应用就是hessian协议。

在这之后就不会像钱买你这么详细的说每一个功能了

LinkedList基本操作

public class TestLinkedList {
    public static void main(String[] agrs){
        List<String> linkedList = new LinkedList<String>();

        //添加功能:
        linkedList.add("a");
        linkedList.add("b");
        linkedList.add("c");
        linkedList.add("d");

        //修改功能:
        linkedList.set(0,"hello");
        linkedList.set(1,"world");
        System.out.println("LinkedList当前内容:"+ linkedList.toString());

        //获取功能:
        String element = linkedList.get(0);
        System.out.println(element);

        //遍历集合:(LinkedList实际的跌倒器是ListItr对象)
        Iterator<String> iterator =  linkedList.iterator();
        while(iterator.hasNext()){
            String next = iterator.next();
            System.out.println(next);
        }
        //for循环迭代集合:
        for(String str:linkedList){
            System.out.println(str);
        }

        //判断功能:
        boolean isEmpty = linkedList.isEmpty();
        boolean isContains = linkedList.contains("TrueDei");

        //长度功能:
        int size = linkedList.size();

        //删除功能:
        linkedList.remove(0);
        linkedList.remove("TrueDei");
        linkedList.clear();
        System.out.println("LinkedList当前容量:" + linkedList.size());
    }
}

结果:

LinkedList当前内容:[hello, world, c, d]
hello
hello
world
c
d
hello
world
c
d

(4)四杀 Quadra kill (消灭敌人:Set之HashSet)

HashSet简单的理解就是HashSet对象中不能存储相同的数据,存储数据时是无序的。但是HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的所以取数据也是按照哈希值取得。

        Set<String> set = new HashSet<>();
        //新增单个数据
        set.add("a");
        set.add("b");
        Set<String> set2 = new HashSet<>();
        //新增单个数据
        set.add("c") ;

        //把set2添加到set中
        set.addAll(set2);

        //指定删除的数据
        set.remove("a");
        //删除set中包含set2的所有数据
        set.removeAll(set2);

        //清空
        set.clear();
        
        //存储了多少个元素
        set.size();

(5)五杀 Penta kill (消灭敌人:Set之TreeSet)

和HashSet的用法差不多,但是看到Tree就想到了存储形式肯定是树的数据结构了。

        Set<String> set = new TreeSet<>();
        //新增单个数据
        set.add("a");
        set.add("b");
        Set<String> set2 = new TreeSet<>();
        //新增单个数据
        set.add("c") ;

        //把set2添加到set中
        set.addAll(set2);

        //指定删除的数据
        set.remove("a");
        //删除set中包含set2的所有数据
        set.removeAll(set2);

        //清空
        set.clear();

        //存储了多少个元素
        set.size();

(6)大杀特杀 Killing Spring (消灭敌人:Queue之LinkedList)

Linkedlist是线性数据结构,其中元素不存储在连续的位置,每个元素都是具有数据部分和地址部分的独立对象。元素使用指针和地址进行链接。每个元素被称为节点。由于插入和删除的动态性和易用性,它们优于阵列。它也有一些缺点,比如节点不能直接访问,我们需要从头开始,然后通过链接到达我们希望访问的节点。

为了将元素存储在链表中,我们使用一个双向链表,它提供了一个线性数据结构,并且还用于继承一个抽象类并实现list和deque接口。

在Java中,LinkedList类实现了列表接口。LinkedList类也包含像其他java集合一样的各种构造函数和方法。

1.增

public boolean add(E e)//链表末尾添加元素,返回是否成功;
public void add(int index, E element)//向指定位置插入元素;
public boolean addAll(Collection<? extends E> c)//将一个集合的所有元素添加到链表后面,返回是否成功;
public boolean addAll(int index, Collection<? extends E> c)//将一个集合的所有元素添加到链表的指定位置后面,返回是否成功;
public void addFirst(E e)//添加到第一个元素;
public void addLast(E e)//添加到最后一个元素;
public boolean offer(E e)//向链表末尾添加元素,返回是否成功;
public boolean offerFirst(E e)//头部插入元素,返回是否成功;
public boolean offerLast(E e)//尾部插入元素,返回是否成功;

2.删

public void clear()//清空链表;
public E removeFirst()//删除并返回第一个元素;
public E removeLast()//删除并返回最后一个元素;
public boolean remove(Object o)//删除某一元素,返回是否成功;
public E remove(int index)//删除指定位置的元素;
public E poll()//删除并返回第一个元素;
public E remove()//删除并返回第一个元素;

3.查

public boolean contains(Object o)//判断是否含有某一元素;
public E get(int index)//返回指定位置的元素;
public E getFirst()// 返回第一个元素;
public E getLast()//返回最后一个元素;
public int indexOf(Object o)//查找指定元素从前往后第一次出现的索引;
public int lastIndexOf(Object o)//查找指定元素最后一次出现的索引;
public E peek()//返回第一个元素;
public E element()//返回第一个元素;
public E peekFirst()//返回头部元素;
public E peekLast()//返回尾部元素;

4.改

public E set(int index, E element)//设置指定位置的元素;

5.遍历

for (int size = linkedList.size(), i = 0; i < size; i++) {
    System.out.println(linkedList.get(i));
}
for (String str: linkedList) {
    System.out.println(str);
}
Iterator iter = linkedList.iterator();
while (iter.hasNext()) {
    System.out.println(iter.next());
}

6.其他

public Object clone()//克隆该列表;
public Iterator<E> descendingIterator()//返回倒序迭代器;
public int size()//返回链表元素个数;
public ListIterator<E> listIterator(int index)//返回从指定位置开始到末尾的迭代器;
public Object[] toArray()//返回一个由链表元素组成的数组;
public <T> T[] toArray(T[] a)//返回一个由链表元素转换类型而成的数组;

7.测试

新闻实体类

/**
 * 新闻类
 */
public class News {
    private int id;                //Id
    private String title;        //标题
    private String author;        //内容
    
    /**
     * 构造方法
     */
    public News() {}
    public News(int id, String title, String author) {
        super();
        this.id = id;
        this.title = title;
        this.author = author;
    }

    /**
     * setter getter
     */
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }

}

新闻测试类 LinkedList

import java.util.LinkedList;

/**
 * 新闻测试类 LinkedList
 */
public class NewsTest2 {
    public static void main(String[] args) {
        //创建链表新闻集合
        LinkedList<News> list=new LinkedList<News>();

        //创建对象
        News n1=new News(1,"春天到了","小鱼");
        News n2=new News(2,"夏天到了","小鸡");
        News n3=new News(3,"秋天到了","小狗");
        News n4=new News(4,"冬天到了","小猫");    
        
        //添加对象
        list.add(n1);        //对象放入集合
        list.add(1,n2);        //在指定下标放入集合
        list.addFirst(n3);    //在首添加对象
        list.addLast(n4);    //在尾添加对象
        list.set(1, n1);    //在index索引位置的元素替换对象
        
        //输入新闻集合
        for(News news:list) {
            System.out.print(news.getId()+","+news.getTitle()+news.getAuthor());
            System.out.println();
        }
        
        //get取出对象
        System.out.println("指定下标取出对象:"+list.get(1));
        System.out.println("取出第一个对象:"+list.getFirst());
        System.out.println("取出末尾的对象:"+list.getLast());
        
        //remove删除对象
        System.out.println("删除对象返回boolean:"+list.remove(n1));
        System.out.println("删除第一个对象:"+list.removeFirst());
        System.out.println("删除最后的对象:"+list.removeLast());
    }
}

(7)无人能挡 Unstoppable(消灭敌人:Queue之BlockingQueue)

一个特殊的队列:BlockingQueue,如果BlockingQueue是空的,从BlockingQueue取东西的操作将会被阻断进入 等待状态,直到BlockingQueue进了东西才会被唤醒,同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等 待状态,直到BlockingQueue里有空间时才会被唤醒继续操作。

本例实现篮子程序,这个篮子中最多能放得苹果数可以随意指定。当篮子满时,生产者进入等待状态,当篮子空时,消费者等待。

BlockingQueue定义的常用方法如下:

add(anObject):把anObject加到BlockingQueue里,如果BlockingQueue可以容纳,则返回true,否则抛出异常。
offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false。
put(anObject):把anObject加到BlockingQueue里,如果BlockingQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里有空间再继续。
poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null。
take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的对象被加入为止。

BlockingQueue有四个具体的实现类,根据不同需求,选择不同的实现类:

ArrayBlockingQueue:规定大小的BlockingQueue,其构造函数必须带一个int参数来指明其大小。其所含的对象是以FIFO(先入先出)顺序排序的。

LinkedBlockingQueue:大小不定的BlockingQueue,若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定。其所含的对象是以FIFO顺序排序的。

PriorityBlockingQueue:类似于LinkedBlockingQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数所带的Comparator决定的顺序

SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的。

LinkedBlockingQueueArrayBlockingQueue比较起来,它们背后所用的数据结构不一样,导致 LinkedBlockingQueue的数据吞吐量大于ArrayBlockingQueue,但在线程数量很大时其性能的可预见性低于 ArrayBlockingQueue

import java.util.concurrent.BlockingQueue;  
/** 
 * to-do. 
 * 
 * @author Denghaiping 
 * @version 1.0 
 */  
public class Fetcher implements Runnable  
{  
  @SuppressWarnings("unused")  
  private BlockingQueue<String> queue = null ;  
  
  public Fetcher(BlockingQueue<String> queue)  
  {  
    this.queue = queue;  
  }  
  
  public void run()   
  {  
    try {  
      while (true) {  
        queue.put("segment-name-"+i);  
        System.out.println("ThreadName : "+ Thread.currentThread().getName() +" 生产完成");  
      }     
    } catch (InterruptedException ex) {  
      ex.printStackTrace();      
    }     
  }  
}      
import java.util.concurrent.ArrayBlockingQueue;  
import java.util.concurrent.BlockingQueue;  
/** 
 * to-do. 
 * 
 * @author Denghaiping 
 * @version 1.0 
 */  
public class Indexer implements Runnable  
{  
  
  private  BlockingQueue<String> queue ;  
  public Indexer(BlockingQueue<String> queue)  
  {  
    this.queue = queue;  
  }  
  
  public void run()  
  {  
    try {  
      while(true) {  
        Thread.sleep(1000);  
        String name = queue.take();  
        System.out.println("ThreadName : " +Thread.currentThread().getName()+ " 消费完成 " +name);  
      }  
    } catch (InterruptedException ex) {  
      ex.printStackTrace();   
    }  
  }  
}   
import java.util.concurrent.*;  
  
/** 
 * to-do. 
 */  
public class TestConsumer  
{  
  private static BlockingQueue<String> queue = new ArrayBlockingQueue<String> (10);  
    
    
  public static void main(String [] args)   
  {  
    ExecutorService service = Executors.newCachedThreadPool();    
    Fetcher producer = new Fetcher(queue);    
    Indexer consumer = new Indexer(queue);    
    Indexer consumer1 = new Indexer(queue);    
    service.submit(producer);    
    service.submit(consumer);  
    service.submit(consumer1);  
    // 程序运行5s后,所有任务停止    
    try {  
      Thread.sleep(5000);  
    } catch (InterruptedException e) {  
      e.printStackTrace();  
    }  
    //service.shutdownNow();    
  }  
}  

(8)主宰比赛 Dominating (消灭敌人:Map之HashMap)

首先恭喜你闯到这一关,过7关斩7将,666,咱们继续,或者可以收藏下,以后看

Hashmap的存值:

         ///*Integer*/map.put("1", 1);//向map中添加值(返回这个key以前的值,如果没有返回null)
         HashMap<String, Integer> map=new HashMap<>();
         System.out.println(map.put("1", 1));//null
         System.out.println(map.put("1", 2));//1
     }

Hashmap的取值:

        HashMap<String, Integer> map=new HashMap<>();
        map.put("DEMO", 1);
        /*Value的类型*///得到map中key相对应的value的值
        System.out.println(map.get("1"));//null
        System.out.println(map.get("DEMO"));//1

Hashmap的判断为空:

       HashMap<String, Integer> map=new HashMap<>();
        /*boolean*///判断map是否为空
        System.out.println(map.isEmpty());//true
        map.put("DEMO", 1);
        System.out.println(map.isEmpty());//false

Hashmap判断是否含有key:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*boolean*///判断map中是否存在这个key
        System.out.println(map.containsKey("DEMO"));//false
        map.put("DEMO", 1);
        System.out.println(map.containsKey("DEMO"));//true
    }

Hashmap判断是否含有value:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*boolean*///判断map中是否存在这个value
        System.out.println(map.containsValue(1));//false
        map.put("DEMO", 1);
        System.out.println(map.containsValue(1));//true
    }

Hashmap删除这个key值下的value:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*Integer*///删除key值下的value
        System.out.println(map.remove("1"));//null
        map.put("DEMO", 2);
        System.out.println(map.remove("DEMO"));//2(删除的值)
    }

Hashmap显示所有的value值:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*Collection<Integer>*///显示所有的value值
        System.out.println(map.values());//[]
        map.put("DEMO1", 1);
        map.put("DEMO2", 2);
        System.out.println(map.values());//[1, 2]
    }

Hashmap的元素个数:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*int*///显示map里的值得数量
        System.out.println(map.size());//0
        map.put("DEMO1", 1);
        System.out.println(map.size());//1
        map.put("DEMO2", 2);
        System.out.println(map.size());//2
    }

Hashmap删除这个key值下的value:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*SET<String>*///显示map所有的key
        System.out.println(map.keySet());//[]
        map.put("DEMO1", 1);
        System.out.println(map.keySet());//[DEMO1]
        map.put("DEMO2", 2);
        System.out.println(map.keySet());//[DEMO1, DEMO2]
    }

Hashmap显示所有的key和value:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*SET<map<String,Integer>>*///显示所有的key和value
        System.out.println(map.entrySet());//[]
        map.put("DEMO1", 1);
        System.out.println(map.entrySet());//[DEMO1=1]
        map.put("DEMO2", 2);
        System.out.println(map.entrySet());//[DEMO1=1, DEMO2=2]
    }

Hashmap添加另一个同一类型的map下的所有制:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        HashMap<String, Integer> map1=new HashMap<>();
        /*void*///将同一类型的map添加到另一个map中
        map1.put("DEMO1", 1);
        map.put("DEMO2", 2);
        System.out.println(map);//{DEMO2=2}
        map.putAll(map1);
        System.out.println(map);//{DEMO1=1, DEMO2=2}
    }

Hashmap删除这个key和value:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*boolean*///删除这个键值对
        map.put("DEMO1", 1);
        map.put("DEMO2", 2);
        System.out.println(map);//{DEMO1=1, DEMO2=2}
        System.out.println(map.remove("DEMO2", 1));//false
        System.out.println(map.remove("DEMO2", 2));//true
        System.out.println(map);//{DEMO1=1}
    }

Hashmap替换这个key的value:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*value*///判断map中是否存在这个key
        map.put("DEMO1", 1);
        map.put("DEMO2", 2);
        System.out.println(map);//{DEMO1=1, DEMO2=2}
        System.out.println(map.replace("DEMO2", 1));//2
        System.out.println(map);//{DEMO1=1, DEMO2=1}
    }

清空这个hashmap:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*void*///清空map
        map.put("DEMO1", 1);
        map.put("DEMO2", 2);
        System.out.println(map);//{DEMO1=1, DEMO2=2}
        map.clear();//2
        System.out.println(map);//{}
    }

Hashmap的克隆:

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*object*///克隆这个map
        map.put("DEMO1", 1);
        map.put("DEMO2", 2);
        System.out.println(map.clone());//{DEMO1=1, DEMO2=2}
        Object clone = map.clone();
        System.out.println(clone);//{DEMO1=1, DEMO2=2}
    }

如果当前 Map 不存在键 key 或者该 key 关联的值为 null,那么就执行 put(key, value);否则,便不执行 put 操作:

public static void main(String[] args) {
		HashMap<String, Integer> map=new HashMap<>();
		/*boolean*///判断map中是否存在这个key
		map.put("DEMO1", 1);
		map.put("DEMO2", 2);
		System.out.println(map);//{DEMO1=1, DEMO2=2}
		System.out.println(map.putIfAbsent("DEMO1", 12222));//1
		System.out.println(map.putIfAbsent("DEMO3", 12222));//null
		System.out.println(map);//{DEMO1=1, DEMO2=2,DEMO3=12222}
	}

如果当前 Map 的value为xx时则值为xx否则为xx:(java8新增方法)compute 方法更适用于更新 key 关联的 value 时,新值依赖于旧值的情况 :

public static void main(String[] args) {
        HashMap<String, Integer> map=new HashMap<>();
        /*boolean*///当这个value为null时为1,否则为3
        map.put("DEMO1", 1);
        map.put("DEMO2", 2);
        System.out.println(map);//{DEMO1=1, DEMO2=2}
        map.compute("DEMO2", (k,v)->v==null?1:3);
        System.out.println(map);//{DEMO1=1, DEMO2=3}
    }

(9)如同神一般了 GodLike (消灭敌人:Map之TreeMap)

TreeMap中的元素默认按照keys的自然排序排列。对Integer来说,其自然排序就是数字的升序;对String来说,其自然排序就是按照字母表排序)

构造函数
TreeMap():创建一个空TreeMap,keys按照自然排序

TreeMap<Integer, String> treeMap = new TreeMap<>();

TreeMap(Comparator comparator):创建一个空TreeMap,按照指定的comparator排序

TreeMap<Integer, String> map = new TreeMap<>();
map.put(3, "val");
map.put(2, "val");
map.put(1, "val");
map.put(5, "val");
map.put(4, "val");
System.out.println(map); // {5=val, 4=val, 3=val, 2=val, 1=val}

TreeMap(Map m):由给定的map创建一个TreeMap,keys按照自然排序

Map<Integer, String> map = new HashMap<>();
map.put(1, "val");
...
TreeMap<Integer, String> treeMap = new TreeMap<>(map);

TreeMap(SortedMap m):由给定的有序map创建TreeMap,keys按照原顺序排序

常用方法
增添元素
V put(K key, V value):将指定映射放入该TreeMap中
V putAll(Map map):将指定map放入该TreeMap中

删除元素
void clear():清空TreeMap中的所有元素
V remove(Object key):从TreeMap中移除指定key对应的映射

修改元素
V replace(K key, V value):替换指定key对应的value值
boolean replace(K key, V oldValue, V newValue):当指定key的对应的value为指定值时,替换该值为新值

查找元素
boolean containsKey(Object key):判断该TreeMap中是否包含指定key的映射
boolean containsValue(Object value):判断该TreeMap中是否包含有关指定value的映射
Map.Entry<K, V> firstEntry():返回该TreeMap的第一个(最小的)映射
K firstKey():返回该TreeMap的第一个(最小的)映射的key
Map.Entry<K, V> lastEntry():返回该TreeMap的最后一个(最大的)映射
K lastKey():返回该TreeMap的最后一个(最大的)映射的key
v get(K key):返回指定key对应的value
SortedMap<K, V> headMap(K toKey):返回该TreeMap中严格小于指定key的映射集合
SortedMap<K, V> subMap(K fromKey, K toKey):返回该TreeMap中指定范围的映射集合(大于等于fromKey,小于toKey)

遍历接口
Set<Map<K, V>> entrySet():返回由该TreeMap中的所有映射组成的Set对象
void forEach(BiConsumer<? super K,? super V> action):对该TreeMap中的每一个映射执行指定操作
Collection<V> values():返回由该TreeMap中所有的values构成的集合

其他方法
Object clone():返回TreeMap实例的浅拷贝
Comparator<? super K> comparator():返回给该TreeMap的keys排序的comparator,若为自然排序则返回null
int size():返回该TreepMap中包含的映射的数量

TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(1, "a");
treeMap.put(2, "b");
treeMap.put(3, "c");
treeMap.put(4, "d"); // treeMap: {1=a, 2=b, 3=c, 4=d}

treeMap.remove(4); // treeMap: {1=a, 2=b, 3=c}
int sizeOfTreeMap = treeMap.size(); // sizeOfTreeMap: 3

treeMap.replace(2, "e"); // treeMap: {1=a, 2=e, 3=c}

Map.Entry entry = treeMap.firstEntry(); // entry: 1 -> a
Integer key = treeMap.firstKey(); // key: 1
entry = treeMap.lastEntry(); // entry: 3 -> c
key = treeMap.lastKey(); // key: 3
String value = treeMap.get(3); // value: c
SortedMap sortedMap = treeMap.headMap(2); // sortedMap: {1=a}
sortedMap = treeMap.subMap(1, 3); // sortedMap: {1=a, 2=e}

Set setOfEntry = treeMap.entrySet(); // setOfEntry: [1=a, 2=e, 3=c]
Collection<String> values = treeMap.values(); // values: [a, e, c]
treeMap.forEach((integer, s) -> System.out.println(integer + "->" + s)); 
// output:
// 1 -> a
// 2 -> e
// 3 -> c

(10)超神了 Legendary (消灭敌人:Map之HashTable)

Hashtable底层是一个哈希表,它是一个线程安全的集合,单线程集合,速度慢,Hashtable集合不能存储null值,null键。

HashMap集合底层是一个哈希表,是线程不安全集合,是一个多线程集合,不过它的速度很快,可以存储null值,null键。

实在是写不动了,现在写博客的时候,字数太多都有点卡
随手截个图
在这里插入图片描述
void clear(): 将此哈希表清空,使其不包含任何键。
Object clone():创建此哈希表的浅表副本。
boolean contains(Object value):测试此映射表中是否存在与指定值关联的键。
boolean containsKey(Object key): 测试指定对象是否为此哈希表中的键。
boolean containsValue(Object value): 如果此 Hashtable 将一个或多个键映射到此值,则返回 true。
Enumeration<V> elements():返回此哈希表中的值的枚举。
Set<Map.Entry<K,V>> entrySet():返回此映射中包含的键的 Set 视图。
boolean equals(Object o):按照 Map 接口的定义,比较指定 Object 与此 Map 是否相等。
V get(Object key): 返回指定键所映射到的值,如果此映射不包含此键的映射,则返回 null. 更确切地讲,如果此映射包含满足 (key.equals(k)) 的从键 k 到值 v 的映射,则此方法返回 v;否则,返回 null。
int hashCode(): 按照 Map 接口的定义,返回此 Map 的哈希码值。
boolean isEmpty():测试此哈希表是否没有键映射到值。
Enumeration<K> keys():返回此哈希表中的键的枚举。
Set<K> keySet():返回此映射中包含的键的 Set 视图。
V put(K key, V value): 将指定 key 映射到此哈希表中的指定 value。
void putAll(Map<? extends K,? extends V> t): 将指定映射的所有映射关系复制到此哈希表中,这些映射关系将替换此哈希表拥有的、针对当前指定映射中所有键的所有映射关系。
protected void rehash():增加此哈希表的容量并在内部对其进行重组,以便更有效地容纳和访问其元素。
V remove(Object key):从哈希表中移除该键及其相应的值。
int size():返回此哈希表中的键的数量。
String toString():返回此 Hashtable 对象的字符串表示形式,其形式为 ASCII 字符 ", " (逗号加空格)分隔开的、括在括号中的一组条目。
Collection<V> values():返回此映射中包含的键的 Collection 视图。

四、遍历数据超强总结(JAVA7+JAVA8)

(1)JAVA7for循环

/*************JAVA7中的遍历***************/
//for循环
for (int i = 0; i < list.size(); i++) {
    System.out.print(list.get(i)+" ");
}

(2)JAVA7增强for循环

//增强for循环
for (Integer integer : list) {
    System.out.print(integer+" ");
}

(3)JAVA7 迭代器循环

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

(4)JAVA8forEach遍历

//Java8中的forEach遍历
list.forEach(new Consumer<Integer>() {
    @Override
    public void accept(Integer integer) {
        System.out.print(integer+" ");
    }
});

(5)JAVA8 soft排序

//可以使用soft排序,compare应该很熟的才对
Collections.sort(list, new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);
    }
});

(6)JAVA8 使用Lambda表达式遍历

//使用Lambda表达式
System.out.print("使用JAVA8中的Lambda表达式遍历:");
list.forEach(integer -> System.out.print(integer + " "));

(7)JAVA8 使用Lambda表达式sort排序

//soft排序也可以使用Lambda表达式
Collections.sort(list,((o1, o2) -> {return o1.compareTo(o2);}));

五、补充资料

(一)java中list最多可以存储多少条数据

从语言上来看,java.util.List是个接口,其下有N多实现,最常用的是ArrayList和LinkedList及其各种继承或同步化实现(如Vector/Queue/Stack这些的)ArrayList内部是拿数组存储,那么上限就是Integer.MAX_VALUELinkedList内部是个链表,理论上是无限的另外,List里放的东西都是在内存里的(当然你也可以自己实现一个放磁盘上的),因此能放多少也取决于你放的东西的大小以及种类。大小方面很容易计算,一个对象如果1K,那400,000个就至少要占用400M的内存(不算其他占用)。而虚拟机内存分类方面,如果是普通对象,一般占用的都是堆(Heap)空间,如果是常量或是类似String.intern()出来的东东,则占用的是永生带(Permanent Generation)。实际开发中,虚拟机默认内存大小根据不同的虚拟机实现有所不同,可以在启动应用时用-Xmx调整最大堆大小,比如调整堆最大大小为2G:java -Xmx2048m cn.gefostudio.App调整永生带最大大小为1G:java -XX:MaxPermSize=1024m cn.gefostudio.App

(二)如何选择合适的Map

  • HashMap可实现快速存储和检索,但其缺点是其包含的元素是无序的,这导致它在存在大量迭代的情况下表现不佳。
  • LinkedHashMap保留了HashMap的优势,且其包含的元素是有序的。它在有大量迭代的情况下表现更好。
  • TreeMap能便捷的实现对其内部元素的各种排序,但其一般性能比前两种map差。
  • LinkedHashMap映射减少了HashMap排序中的混乱,且不会导致TreeMap的性能损失。

六、参考资料

https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html
https://zhidao.baidu.com/question/389467609.html
https://www.xuebuyuan.com/3191095.html
https://www.jianshu.com/p/e11fe1760a3d
https://www.cnblogs.com/yijinqincai/p/10964188.html
https://blog.csdn.net/bluuusea/article/details/79949592
https://www.jianshu.com/p/e11fe1760a3d
https://blog.csdn.net/tao_wei162/article/details/84824425

七、写在后面的废话

有哪里不对的地方欢迎讨论,想凑够25000字,最后200个字实在太难了,我已经困得不行了。现在敲字写进博客得时候,都写不动了,因为字数太多,会卡。

还有80个字就25000了,加油。

大家通过这次得杀敌,一定能掌握不少吧,后来将分享原理性的东西,欢迎大家持续关注哦。

感谢大家支持。

有你的支持,才会写作出更好的文章。

别忘了给个大大的👍,给个大大的关注哦。

在这里插入图片描述

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读