集合进阶(Collection,List,Set,Map,ArrayList,LinkedList, TreeSet,HashSet,HashMap)Stream流,函数式接口以及集合中常见的面试题

集合进阶(Collection,List,Set,Map,ArrayList,LinkedList, TreeSet,HashSet,HashMap等相关知识)和Stream流,函数式接口的理解以及集合中常见的面试题

文章目录


前言

什么叫集合:集合是指具有某种特定性质的具体的或抽象的对象汇总而成的集体。其中,构成集合的这些对象则称为该集合的元素。
JAVA中的集合体系结构:
在这里插入图片描述脑海中有了此体系结构学集合就可以把知识点做相关的连接起来学起来更加的容易,下面就将对相关的知识做阐述

一、Collection

1.Collection集合的概述和使用

在这里插入图片描述
值得注意的是:Collection它不提供此接口的直接表现形式,所以可以用多态的方式以及具体的实现类如:ArrayList,LinkedList, TreeSet,HashSet等来创建Collection对象。

2.常用方法

			常见的增删改查以及判断集合是否为空和得到集合的长度

在这里插入图片描述

3.Collection集合的遍历(迭代器)

在这里插入图片描述
需要注意的是:
这里我提到的是迭代器遍历的方式,不代表只能用迭代器遍历,也可以用for循环以及增强for循环(后面会讲到),只是在不同场景的时候就会有不同的用法而已。
迭代器遍历的时候不能在迭代器遍历的时候通过add添加元素,这样会出现并发修改异常的报错现象。如图所示:在这里插入图片描述
因为在add的时候用的是迭代器的对象,而不是刚开始创建存储数据的对象。而List集合就会有一个特定的迭代器,在使用它的迭代器的时候就不会有并发修改异常,因为这是他特有的,也只有List才有,其他的没有。

4.Collection集合的使用步骤

在这里插入图片描述

二、List

1.List集合的概述

在这里插入图片描述
它就是一个有索引的通过索引进行各种操作的集合

2.List集合的特点

1.有序的:存储与取出的顺序是一致的
2.可重复的:可以存储相同的重复的元素(与set不一样)

3.List特有的方法

在这里插入图片描述

4.列表迭代器

在这里插入图片描述

值得注意的是:
List特有的迭代器前面我已经阐述了,这里我就不过多的阐述了。
但是常用的方法中必须先让迭代的指针向后移动后才能前移动,要不然会报错,也就是说:

注意:用那个  while (iterator.hasPrevious()){
            String s = iterator.previous();
            System.out.println(s);
        }的时候首先指针要到最后才行,而不能一来就是上面的代码,正确的是ListIterator<String> iterator = list.listIterator();
        System.out.println("----------------");
        while (iterator.hasNext()){
            String s = iterator.next();
            System.out.println(s);
        }
        while (iterator.hasPrevious()){
            String s = iterator.previous();
            System.out.println(s);
        }

5.增强for循环

举个例子,一看就懂了

package other;

import java.util.ArrayList;
import java.util.Collection;

public class test{
    public static void main(String[] args) {
        Collection<String> list=new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        for (String s:list) {
            System.out.println(s);
        }
    }
}

其中String s 就可理解为list集合中元素的类型+变量名
注意的点
其内部就是一个iterator迭代器,所以使用不当会出现并发修改异常
如何选择三种遍历的方式呢?`
1.如果只是为了单纯的遍历的话就可以用增强for循环
2.如果遍历后需要对数据进行操作的话就要用到for循环
3.如果要求你用迭代器的话就用迭代器

6.数据结构

栈
	先进后出
队列
	先进先出
	链表
		注意一个结点包含的是三个东西(地址,数据,下一个结点的地址)
	数组与链表比较的区别
		数组是查询快增删慢,查询可以通过索引所以快,增删而是需要移动位置所以慢
		链表是增删快查询慢,因为链表的查询是每次都要重头开始查询所以慢,而增删不需要移动位置,而是改改地址就可以了
	list集合子类的特点
		ArrayList
			底层数据是数组:查询快,增删慢
		LinkedList
			底层数据是链表,查询慢,增删快

三、Set

1.list集合的概述和特点

一、没有索引不能用for循环
二、不包含重复的元素

2.哈希值

在这里插入图片描述
索引有了哈希值这个概念才会使得set这个集合不包含重复的元素集合。

3.HashSet概述和特点

1.底层数据结构是哈希表
2.对集合的迭代顺序不做任何保证,也就是说不保证存储和取出的顺序一致
3.没有带索引的方法,所以不能用for循环
4.由于是Set集合,所以是不包含重复元素的集合

4.常见数据结构之哈希表

1.在JDK8之前,底层采用数组+链表实现,可以说是一个元素为链表的数组
2.在JDK8之后,在长度比较长的时候,底层实现了优化
当链表超过阈值,比如说8的时候,就会写入树中

如图所示是数组+链表
在这里插入图片描述

5.LinkedHashset集合的概述和特点

1.哈希表和链表实现的Set接口,具有可预测的迭代次序
2.由链表保证元素有序,也就是说元素的存储和取出的顺序是一致的
3.由哈希表保证元素的唯一,也就是说没有重复的元素

6.TreeSet集合的概述和特点

在这里插入图片描述
无参TreeSet(),根据元素的自然顺序进行排序的情况
在这里插入图片描述
在这里插入图片描述
带参TreeSet(Comparator),根据指定的比较器进行排序的情况

在这里插入图片描述
个人的理解就是:
1.无参的情况,如果只是用的整型数组以及String数组的话,底层会自动的自然排序,但是当我们写类的时候,自然排序就实现不了排序的情况,所以就要实现Comparable接口来写自己的排序情况来实现排序
2.有参数的情况:就是利用匿名内部类的方式进行实现Comparator比较器来实现自己想要的排序情况

7.泛型的概述

在这里插入图片描述

1.泛型类的定义格式
格式:
修饰符 class 类名<类型>{}
范例:
pubic class A{}
此处T可以随便写为任意标识,常见的如T,E,K,V等形式的参数常用于表示泛型
2.泛型方法
泛型方法的定义格式:
修饰符<类型>返回值类型 方法名(类型 变量名){}
范例:
public void show(T t){}
3.泛型接口
在这里插入图片描述

8.可变参数

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

四.Map

1.Map概述

·Interface Map <K,V> K:键的类型; V:值的类型
·将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值
创建Map集合的对象
·多态的方式
·具体的实现类HashMap
Map是一个接口,所以只能通过多态的方式以及具体的实现类来使用它

2.Map的基本功能

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

3.Map集合的遍历

方式一:
我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
遍历思路
·把所有的丈夫给集中起来
·遍历丈夫的集合,获取到每一个丈夫
·根据丈夫去找对应的妻子

转换为Map集合中的操作:
·获取所有键的集合。用keySet()方法实现
·遍历键的集合,获取到每一个键。用增强for实现
·根据键去找值。用get(Object key)方法实现
方式二
我们刚才存储的元素都是成对出现的,所以我们把Map看成是一个夫妻对的集合
遍历思路
·获取所有结婚证的集合
·遍历结婚证的集合,得到每一个结婚证
·根据结婚证获取丈夫和妻子

转换为Map集合中的操作:
·获取所有键值对对象的集合
Set<Map.Entry<K,V>>entrySet():获取所有键值对对象的集合
·遍历键值对对象的集合,得到每一个键值对对象
用增强for实现,得到每一个Map.Entry
·根据键值对对象获取键和值
用getKey()得到键
用getValue()得到值

4.Collecitons的概述

针对集合操作的工具类

常用方法
·public static <T extends Comparable<? super T>> void sort(List list):将指定的列表按升序排序
·public static void reverse(List<?>list):反转指定列表中元素的顺序
·public static void shuffle(List <?> list):使用默认的随机源随机排列指定的列表

五.函数式接口

1.函数式接口的概述

函数式接口:有且仅有一个抽象方法的接口
Java中的函数式编程体现就是Lambda表达式,所以函数式接口就是可以适用于Lambda适用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利的进行推导

如何检测一个接口是不是函数式接口呢?
·@FunctionalInterface
·放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败

注意
·我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上注解

2.函数式接口作为方法的参数

如果方法的参数是一个函数式接口,我们可以使用Lambda表达式作为参数传递
·startThread(() ->System.out.println(Thread.currentThread().getName() + “线程启动了”));

3.函数式接口作为方法的返回值

如果方法的返回值是一个函数式接口,我们可以使用Lambda表达式作为结果返回
·private static ComparatorgetComparator(){
return (s1, s2) -> s1.length() - s2.length();
}

4.常见的函数式接口

Supplier接口:
Supplier:包含一个无参的方法
·T get():获得结果
·该方法不需要参数,它会按照某种实现逻辑(由Lambda表达式实现)返回一个数据
·Supplier接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类的数据供我们使用
Consumer接口
Consumer:包含两个方法
·void accept(T t):对给定的参数执行此操作
·default ConsumerandThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作
·Consumer接口也被称为消费型接口,它消费的数据的数据类型由泛型指定
Predicate接口
Predicate:常用的四个方法
·boolean test(T t):对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
·default Predicatenegate():返回一个逻辑的否定,对应逻辑非
·default Predicateand(Predicate other):返回一个组合判断,对应短路与
·default Predicateor(Predicate other):返回一个组合判断,对应短路或
·Predicate接口通常用于判断参数是否满足指定的条件
Function接口
Function<T,R>:常用的两个方法
·R apply(T t):将此函数应用于给定的参数
·default Function andThen(Function after):返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果
·Function<T,R>接口通常用于对参数进行处理,转换(处理逻辑由Lambda表达式实现),然后返回一个新的值

六.Stream流

1.Stream的三种生成方式

生成流,中间操作,生成操作

2.生成流

通过数据源(集合,数组等)生成流
list.stream()
常见的生成方式:
在这里插入图片描述
代码的实现
在这里插入图片描述

3.中间操作

一个流后面可以跟随零个或者多个中间操作,其目的主要是打开流,做出某种程度的数据过滤、映射,然后返回一个新的流,交给下一个操作使用
filter()
常见的中间方法
在这里插入图片描述
在这里插入图片描述

4.终结操作

在这里插入图片描述

5.收集操作

在这里插入图片描述

七.JAVA集合中的各种区别

1.ArrayList和LinkedList区别

两个都是List的接口,都是非线程安全的
ArrayList是基于动态数组的数据结构,而LinkedList是基于链表的数据结构
对于随机访问get和set(查询操作),ArrayList要优于LinkedList,因为LinkedList要移动指针
对于增删操作(add和remove),LinkedList优于ArrayList

2.HashMap和TreeMap应该怎么选择

HashMap可实现快速存储和检索,但缺点是包含的元素是无序的,适用于在Map中插入、删除和定位元素
TreeMap能便捷的实现对其内部元素的各种排序,但其一般性能比HashMap差,适用于按自然顺序或自定义顺序遍历键(key)
jdk1.7和jdk1.8中HashMap的主要区别
底层实现由之前的“数组+链表”改为“数组+链表+红黑树”
jdk1.8中,当链表节点较少时仍然以链表存在,当链表节点较多时,默认是大于8时会转为红黑树

3.HashSet和TreeSet区别

HashSet不能保证元素的排列顺序,TreeSet是SortedSet接口的唯一实现类,可以确保集合元素处于排序状态
HashSet底层用的是哈希表,TreeSet采用的数据结构是红黑树(红黑树是一种特定类型的二叉树)
HashSet中元素可以是null,但只能有一个,TreeSet不允许放入null
一般使用HashSet,如果需要排序的功能时,才使用TreeSet(性能原因)

4.当向集合中插入对象时,如何判别在集合中是否已经存在该对象,比如Set确保存储对象的唯一,并判断是不是同个对象呢?

依据hashCode()和equals()进行判断,所以Set存储的对象必须重写这两个方法
判断两个对象是否一样,首先判断插入obj的hashcode值是否存在,hashcode值不存在则直接插入集合,值存在则还需判断equals方法判断对象是否相等

八.集合中常见的面试题(进一步加深对集合的理解)

1、介绍Collection框架的结构

集合是Java中的一个非常重要的一个知识点,主要分为List、Set、Map、Queue三大数据结构。它们在Java中的结构关系如下:
在这里插入图片描述
Collection接口是List、Set、Queue的父级接口。

Set接口有两个常用的实现类:HashSet和TreeSet。List接口的常用接口有ArrayList和Vector接口。

Map接口有两个常用的实现类:Hashtable和HashMap。

2、Collection框架中实现比较要实现什么接口

要实现比较有两种方式:第一种,实体类实现Comparable接口,并实现 compareTo(T t) 方法,我们称为内部比较器。第二种,创建一个外部比较器,这个外部比较器要实现Comparator接口的 compare(T t1, T t2)。

由此可见,如果你希望该实体类在放入集合的时候能按照你希望的方式排序(如果集合支持),那么你需要让实体类实现Comparable接口。如果你只是需要简单比较两个实体类的大小,最后返回一个结果,那么用Comparator接口实现一个外部比较器更合适。
3、ArrayList和Vector的区别(是否有序、是否重复、数据结构、底层实现)

ArrayList和Vector都实现了List接口,他们都是有序集合,并且存放的元素是允许重复的。它们的底层都是通过数组来实现的,因此列表这种数据结构检索数据速度快,但增删改速度慢。

而ArrayList和Vector的区别主要在两个方面:

第一,线程安全。Vector是线程安全的,而ArrayList是线程不安全的。因此在如果集合数据只有单线程访问,那么使用ArrayList可以提高效率。而如果有多线程访问你的集合数据,那么就必须要用Vector,因为要保证数据安全。

第二,数据增长。ArrayList和Vector都有一个初始的容量大小,当存储进它们里面的元素超过了容量时,就需要增加它们的存储容量。ArrayList每次增长原来的0.5倍,而Vector增长原来的一倍。ArrayList和Vector都可以设置初始空间的大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。

4、HashMap和Hashtable的区别

HashMap和Hashtable都实现了Map接口,并且都是key-value的数据结构。它们的不同点主要在三个方面:

第一,Hashtable是Java1.1的一个类,它基于陈旧的Dictionary类。而HashMap是Java1.2引进的Map接口的一个实现。

第二,Hashtable是线程安全的,也就是说是线程同步的,而HashMap是线程不安全的。也就是说在单线程环境下应该用HashMap,这样效率更高。

第三,HashMap允许将null值作为key或value,但Hashtable不允许(会抛出NullPointerException)。

5、List 和 Map 区别?(数据结构,存储特点)

这个要从两个方面来回答,一方面是List和Map的数据结构,另一方面是存储数据的特点。在数据结构方面,List存储的是单列数据的集合,而Map存储的是key、value类型的数据集合。在数据存储方面,List存储的数据是有序且可以重复的,而Map中存储的数据是无序且key值不能重复(value值可以重复)。

6、List、Map、Set三个接口,存取元素时,各有什么特点?

List与Set具有相似性,它们都是单列元素的集合,所以,它们有一个功共同的父接口,叫Collection。Set里面不允许有重复的元素,所谓重复,即不能有两个相等(注意,不是仅仅是相同)的对象 ,即假设Set集合中有了一个A对象,现在我要向Set集合再存入一个B对象,但B对象与A对象equals相等,则B对象存储不进去。所以,Set集合的add方法有一个boolean的返回值,当集合中没有某个元素,此时add方法可成功加入该元素时,则返回true,当集合含有与某个元素equals相等的元素时,此时add方法无法加入该元素,返回结果为false。Set取元素时,没法说取第几个,只能以Iterator接口取得所有的元素,再逐一遍历各个元素。

List表示有先后顺序的集合, 注意,不是那种按年龄、按大小、按价格之类的排序。当我们多次调用add(Obj e)方法时,每次加入的对象就像火车站买票有排队顺序一样,按先来后到的顺序排序。有时候,也可以插队,即调用add(int index,Obj e)方法,就可以指定当前对象在集合中的存放位置。一个对象可以被反复存储进List中,每调用一次add方法,这个对象就被插入进集合中一次,其实,并不是把这个对象本身存储进了集合中,而是在集合中用一个索引变量指向这个对象,当这个对象被add多次时,即相当于集合中有多个索引指向了这个对象,如图x所示。List除了可以以Iterator接口取得所有的元素,再逐一遍历各个元素之外,还可以调用get(index i)来明确说明取第几个。

Map与List和Set不同,它是双列的集合,其中有put方法,定义如下:put(obj key,obj value),每次存储时,要存储一对key/value,不能存储重复的key,这个重复的规则也是按equals比较相等。取则可以根据key获得相应的value,即get(Object key)返回值为key 所对应的value。另外,也可以获得所有的key的结合(map.keySet()),还可以获得所有的value的结合(map.values()),还可以获得key和value组合成的Map.Entry对象的集合(map.entrySet())。

List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value值,value可多值。

总结

集合需要在不同的场景使用不同的集合,但是如何用好集合就需要去弄明白集合的底层存储的原理,比如,Map集合键值对中的键其实就是Set集合而值就是Collecttion集合,所以才会有Map集合中键只能是唯一的,而值可以是重复的情况。这就是我举的例子,意思就是要去弄明白,底层的原理,其中底层的原理很重要,明白了底层存储的原理,就会很好的理解和使用各种的集合。

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lnwd___

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

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

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

打赏作者

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

抵扣说明:

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

余额充值