ArrayList集合是一种容器,用来装数据的,类似于数组,但集合的大小可变,开发中也非常有用,为了满足不同的业务场景需求,Java还提供了许多不同的特点的集合
集合体系:单列集合(Collection)、双列集合(Map)
Collection集合体系
Collection
Collection的常用方法
Collection的遍历方式
List集合
特点,特有方法 遍历方式 ArrayList集合的特点及底层原理 LinkedList集合的底层原理和常用方法 Set集
特点 HashSet集合的特点及底层原理 LinkedHashSet集合的特点及底层原理 TreeSet的特点及底层原理 Collection集合的使用总结,集合的并发修改异常问题
Collection的其他相关知识
Stream流
获取Stream流 Stream提供的中间终结方法 Stream提供的常用终结方法
1. Collection 单列集合
2. Map 双列集合
Collection代表单列集合:每个元素(数据)只包含一个值
Map代表双列集合,每个元素包含两个值(键值对)
List系列集合:添加的元素是有序,可重复、有索引
ArrayList、LinkedList:有序、可重复、有索引 Set系列集合:添加的元素是无序、不重复、无索引
HashSet:无序、不重复、无索引 LinkedHashSet:有序、不重复、无索引 TreeSet:按照大小默认升序排序,不重复、无索引
Collection的常用方法
方法名说明Public boolean add(E e)把给定的对象添加到当前集合中Public void clear()清空集合中的所有元素Public boolean remove(E e)把给定的对象在当前集合中删除Public boolean contains(Object obj)判断当前集合中是否包含给定的对象Public boolean isEmpty()判断当前集合是否为空Public int size()返回集合中元素的个数Public Object[] toArray()把集合中的元素,存储到数组中
Collection的遍历方式
迭代器 增强for lambda表达式
迭代器
迭代器是用来遍历集合的专用方式(数组没有迭代器,在Java中迭代器的代表是Iterator)
Collection集合获取迭代器的方法
方法名说明Iterator iterator返回集合中的迭代器对象,该迭代器默认指向当前集合的第一个元素
Iterator迭代器的常见方法
方法名说明boolean hasNext()询问当前位置是否有元素存在,存在返回true,不存在返回falseE next()获取当前位置的元素,并同时将迭代器对象指向下一个元素处
增强for循环
格式
增强for可以用来遍历集合或数组 增强for遍历集合,本质就是迭代器遍历集合的简化写法
lambda表达式遍历集合
得益于JDK 8,开始的新技术lambda表达式,提供了一种更简单更直接的方式来遍历集合
需要使用Collection的如下方法完成
方法名说明default void forEach(Consumer <? super T> action)结合lamdba遍历集合
案例:遍历集合中的自定义对象
需求:展示多部电影
分析:
每部电影都是一个对象,多部电影要用集合装起来 遍历集合中的3个电影对象,输出每部电影的详情信息
特点、特有方法 遍历方式 ArrayList集合的底层原理 LinkedList集合的底层原理
·
List集合的特有方法
List集合因为支持索引,所以多了许多与索引相关的方法,当然,Collection的功能List也继承了
方法名说明void add(int index,E element)在此集合中的指定位置插入指定的元素E remove(int index)删除指定索引处的元素,返回被删除的元素E set(int index,E element)修改指定索引处的元素,返回被修改的元素E get(int index)返回指定索引处的元素
List集合支持的遍历方式
for循环(因为List集合有索引) 迭代器 增强for循环 lamdba表达式
ArrayList集合的底层原理
基于数组实现的(查询快,增删慢) 数组的特点
删除效率低:可能需要把后面很多的数据进行前移 添加效率极低:可能需要把后面很多的数据后移,在添加元素,或者也可能需要进行数组的扩容
ArrayList集合底层存数据的原理
利用无参构造器创建的集合,会在底层创建一个默认长度为0的数组 添加第一个元素时,底层会创建一个新的长度为10的数组 存满时,会扩容1.5倍 如果一次添加多个元素,1.5倍还放不下,则新创建的数组的长度以实际为准 ArrayList集合适合的应用场景
ArrayList适合:根据索引查询数据,比如根据随机索引取数据(高效),或者数据量不是很大时! ArrayList不适合:数据量大的同时,又要频繁的进行增删操作!
LinkedList集合的底层原理
什么是链表?有啥特点
链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址
链表的特点:
查询慢,无论查询哪个数据都要从头开始 链表增删相对(数组)快
单向链表
双向链表
LinkedList新增了许多首尾操作的特有方法
方法名称说明Public void addFirst(E e)在该列表开头插入指定的元素Public void addLast(E e)将指定的元素追加到此列表的末尾Public E getFirst()返回此列表的第一个元素Public E getLast()返回此列表的最后一个元素Public E removeFirst()从此列表中删除并返回第一个元素Public E removeLast()从此列表中删除并返回最后一个元素
LinkedList的应用场景之一:可以用来设计队列(叫号系统、排队系统)
队列:先进先出,后进后出
只是在首尾增删元素,用LinkedList来实现很合适!
LinkedList的应用场景之一:可以用来设计栈
栈:后进先出,先进后出
数据进入栈模型的过程称为:压/进栈(push)
数据离开栈模型的过程称为:弹/出栈(pop)
特点 HashSet集合的底层原理 LinkedHashSet集合的底层原理 TreeSet集合
Set系列集合特点:无序:添加数据的顺序和获取数据顺序不一致,不重复;无索引
HashSet:无序,不重复,无索引 LinkedHashSet:有序,不重复,无索引 TreeSet:排序,不重复,无索引
HashSet集合的底层原理
为什么添加的元素无序、不重复、无索引? 增删改查数据有什么特点,适合什么场景?
哈希值:
就是一个int类型的数值,java中每个对象都有一个哈希值 java中所有对象,都可以调用Object类提供的hashCode方法,返回该对象自己的哈希值
对象哈希值的特点:
同一个对象多次调用hashCode()方法,返回的哈希值是相同的 不同的对象,它们的哈希值一般不相同,但也有可能会相同(哈希碰撞),int(-21亿多 - 21亿多)
HashSet的底层原理:
基于哈希表实现 哈希表是一种增删改查数据,性能都较好的数据结构
哈希表:
JDK8之前,哈希表 = 数组 + 链表 JDK8开始,哈希表 = 数组 + 链表 + 红黑树
JDK8之前HashSet集合的底层原理,基于哈希表:数组 + 链表
创建一个默认长度为16的数组,默认加载因子为0.75,数组名为table 使用元素的哈希值对数组的长度求余,计算出应存入的位置 判断当前位置是否为null,如果是null直接存入该数据 如果不为null,表示当前位置有元素,则调用equals方法比较,相等则不存,不相等,则存入数组
JDK8之前,新元素存入数组,占老元素位置,老元素挂下面 JDK8开始之后,新元素直接挂在老元素下面
JDK8开始之后,HashSet集合的底层原理,基于哈希表:数组 + 链表 + 红黑树
JDK8开始,当链表长度超过8,且数组长度 >= 64时,自动将链表转成红黑数 小结:JDK8开始后,哈希表中引入了红黑树后,进一步提高了操作数据的性能
了解一下数据结构(树)
红黑树,就是可以自平衡的二叉树 红黑树是一种增删改查数据性能相对都较好的结构
深入理解HashSet集合去重复的机制
HashSet集合默认不能对内容一样的两个不同对象去重复
比如内容一样的两个学生对象存入到HashSet集合中去,HashSet集合是不能去重的
如何让HashSet集合能够实现对内容一样的两个不同对象也能去重复?
如果希望Set集合认为2个内容一样的不同对象是重复的,必须重写对象的hashCode() 和 equals()方法
LinkedHashSet:有序、不重复、无索引
依然是基于哈希表(数组、链表、红黑树)实现的 但是,它的每个元素都额外的多了一个双链表的机制记录它前后的位置
TreeSet
特点:不重复,无索引,可排序(默认升序,按照元素的大小,由小到大排序) 底层是基于红黑数实现的排序
注意:
对于数值类型:Integer,Double,默认按照数值本身的大小进行升序 对于字符串类型:默认按照首字符的编号升序排序 对于自定义类型如:Student 对象,TreeSet默认是无法直接排序的
自定义排序规则
TreeSet集合存储自定义类型的对象时,必须指定排序规则
方式一:
让自定义的类实现Comparable接口,重写里面的CompareTo方法,来指定比较规则
方式二:
通过调用TreeSet集合的有参构造器,可以设置Comparator对象(比较器对象)
方法名Public TreeSet(Comparator < ? super E > comparator)
Collection集合的之一总结,集合的并发修改异常问题
如果希望记住元素的添加顺序,需要存储重复的元素,又要频繁的根据索引查询数据?
用ArrayList集合(有序、可重复、有索引),底层基于数组(常用) 如果希望记住元素的添加顺序,且增删首尾数据的情况较多?
用LinkedList集合(有序、可重复、有索引),底层基于双链表实现的 如果不在意元素顺序,也没有重复元素需要存储,只希望增删改查都快?
用HashSet集合,底层基于哈希表实现的(常用) 如果希望记住元素的添加顺序,也没有重复元素需要存储,且希望增删改查都快
用LinkedHashSet集合(有序、不重复、无索引),底层基于哈希表和双链表 如果要对元素进行排序,也没有重复元素需要存储,且希望增删改查都快
使用迭代器遍历集合,又同时在删除集合中的数据时,程序就会出现并发修改异常的错误 由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删除集合中的数据时,程序也会出现并发修改异常。
怎么保证遍历集合时删除数据不出bug?
使用迭代器遍历集合,使用迭代器自己的删除方法删除数据即可 使用for循环遍历
从前往后遍历,但删除元素后做i–操作 倒着遍历集合并删除
可变参数
就是一种特殊的形参,定义在方法、构造器的形参列表里,格式是:
可变参数的特点和好处
特点:可以不传数据给形参,可以传一个数据或者多个数据给形参,也可以传一个数组给形参 好处:常常用来灵活的接收数据
可变参数的注意事项
可变参数在方法内部就是一个数组 一个形参列表中可变参数只能有一个 可变参数必须放在形参列表的最后面
Collections提供的常用静态方法
方法名称说明Public static boolean addAll(collection < ? super T > c,T … elements )给集合批量添加数据Public static void shuffle(List<?> list)打乱List集合中的元素顺序Public static void sort(List list)对list集合中的元素进行升序排序Public static void sort(List list,Comparator< ? super T > c )对list集合中元素,按照比较器对象指定的规则进行排序
案例:斗地主游戏
总共有54张牌 点数:“3”,“4”,“5”,“6”,“7”,“8”,“9”,“10”,“J”,“Q”,“K”,“A”,“2” 花色:“♠”,“♥”,“♣”,“♦” 大小王:“☺”,“☹” 斗地主:发出51张牌,剩下3张作为底牌
分析实现:
在启动游戏房间的时候,应该提前准备好54张牌 接着,需要完成洗牌,发牌,对牌排序,看牌
概述 常用方法 遍历方式 HashMap LinkedHashMap TreeMap 补充知识:集合的嵌套
1.认识Map集合
Map集合称为双列集合,格式:{ key1 = value1 , key2 = value2,key3 = value3,…},一次需要存一对数据作为一个元素 Map集合的每个元素"key = value " 称为一个键值对 | 一个键值对对象 | 一个Entry对象,Map集合也被叫做“键值对集合” Map集合的所有键是不允许重复的,但值可以重复,键和值是 一 一对应的,每一个键只能找到自己对应的值
Map集合在什么业务场景下使用
比如购物车里面的商品列表 { 商品1 = 2 , 商品2 = 3, 商品3 = 2},需要存储一 一对应的数据时,就可以考虑使用Map集合
Map集合体系
Map集合体系的特点
注意:Map系列集合的特点,都是由键决定的,值只是一个附属品,值是不做要求的
HashMap(由键决定特点):无序、不重复、无索引;(用的最多)
LinkedHashMap(由键决定特点):有序,不重复,无索引
TreeMap(由键决定特点):按照键的大小默认升序,不重复,无索引
Map的常用方法
为什么要先学习Map的常用方法?
Map是双列集合的祖宗,它的功能是全班双列集合都可以继承过来使用的
Map的常用方法说明Public V put (K key , V value)添加元素Public int size()获取集合的大小Public void clear()清空集合Public boolean isEmpty()判断集合是否为空,为空返回true,反之Public V get(Object key)根据键获取对应值Public V remove(Object key)根据键删除整个元素,并返回被删除的元素对应的值Public boolean containsValue(Object value)判断是否包含某个值Public Set keySet()获取全部键的Set集合Public Collection values()获取Map集合的全部值的Collection的集合
Map集合的遍历方式
键找值:先获取Map集合全部的键,在通过遍历键来找值 键值对:把"键值对"看成一个整体进行遍历(难度较大) lambda:JDK8开始之后的新技术(非常的简单)
Map集合的遍历方式一:键找值,需要用到Map的如下方法
方法名称说明Public Set keySet()获取所有键的集合Public V get(Object key)根据键获取其对应的值
Map集合的遍历方式二:键值对
Map提供的方法
方法名说明Set < Map.Entry<K,V> > entrySet()获取所有“键值对”的集合
Map.Enrty提供的方法
方法名说明K getkey()获取键V getValue()获取值
Map集合的遍历方式三:Lambda
需要用到Map的如下方法
方法名说明default void forEach(BiConsumer< ? super K , ? super V > action )结合Lambda遍历Map集合
Map集合的案例:统计投票人数
需求:某个班级100名学生,现在需要组织秋游活动,班长提供了四个景点(A,B,C,D),每个学生只能选择一个景点,请统计出最终哪个景点想去的人数最多
分析:
将100个学生选择的数据拿到程序中去,[A,A,B,A,B,C,D…] 准备一个Map集合用于存储统计结果,Map<String,Integer>,键是景点,值是票数 遍历100个学生选择的景点,每遍历一个景点,就看Map集合中是否存在该景点,不存在在存入“ 景点 = 1 ”,存在则其对应的值 +1
HashMap集合的底层原理
HashMap跟HashSet的底层原理是一模一样的,都是基于哈希表实现的 实际上Set系列的底层就是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据而已
HashMap底层是基于哈希表实现的
JDK8之前,哈希表 = 数组 + 链表 JDK8开始之后,哈希表 = 数组 + 链表 + 红黑数 哈希表是一种增删改查数据,性能都较好的数据结构 无序、不重复、无索引(由键决定特点) HashMap的键依赖hashCode()方法和equals()方法保证键的唯一 如果键存储的是自定义类型的对象,可以通过重写hashCode()和equals()方法,这样可以保证多个对象内容一样时,HashMap集合就能认为是重复的
LinkedHashMap集合的底层原理
底层数据结构依然是基于哈希表实现的,只是每个键值对元素,又额外的多了一个双链表机制,记录元素顺序(保证有序) 实际上,原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap 有序、不重复、无索引
TreeMap
特点“不重复、无索引、可排序(按照键的大小默认升序排序,只能对键排序) 原理:TreeMap跟TreeSet集合的底层原理是一样的,都是基于红黑数实现的排序
TreeMap集合同样也支持两种方式来指定排序规则
让类实现Comparable接口,重写比较规则
TreeMap集合有一个有参构造器,支持创建Comparator比较器对象,以便用来指定比较规则
需求:要求在程序中记住如下省份和其对应的城市信息,记录成功后要求可以查询出湖北省的城市信息
分析:定义一个Map集合,键用来表示省份名称,值表示城市名称
注意:城市有多个,可以根据"湖北省"这个键获取对应的值展示即可
认识Stream Stream的常用方法
什么是Stream?
也叫Stream流,是JDK8开始新增的一套API(java.unit.Stream.*),可以用于操作集合或数组的数据 优势:Stream流大量的结合力Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式操作集合或者数组中的数据,代码更简洁,可读性更好
体验Stream流
需求:把集合中所有以“张”开头,且是3个字的元素存储到一个新的集合中去
Steram流的使用步骤
常用方法
获取Stream流
Collection提供的如下方法
方法名说明default Stream stream()获取当前集合对象的Stream流
Arrays类提供的如下方法
方法名说明Public static Stream Stream( T[] array )获取当前数组的Stream
Stream类提供的如下方法
方法名说明Public static Stream of( T…values)获取当前接受数据的Stream流
Stream流常见的中间方法
中间方法指的是调用完成后会返回新的Stream流,可以继续使用(链式编程)
方法名说明Stream filter(Predicate< ? super T> predicate)用于对流中的数据进行过滤Stream sorted()对元素进行升序排序Stream sorted(Comparator <? super T> comparator)按照指定规则排序Stream limit(long maxSize)获取前几个元素Stream skip(long n)跳过前几个元素Stream distinct()去除流中重复的元素 Stream map( Function < ? super T , ? extends R > mapper )对元素进行加工,并返回对应的新流Static Stream concat(Stream a,stream b)合并a和b两个流为一个流
Stream流常见的终结方法
终结方法指的是调用完成后,不会返回新的Sream流,没法继续使用流了
Stream提供的常见终结方法
方法名说明void forEach(Consumer action)对此流运算后的元素执行变量long count()统计此流运算后的元素个数Optional max(Comparator < ? super T > comparator )获取此流运算后的最大值元素Optional min(Comparator < ? super T > comparator )获取此流运算后的最小值元素
收集Stream流:就是把Stream流操作后的结果转回到集合或数组中去返回
Stream流:方便操作集合 / 数组的手段;集合 / 数组:才是开发中的目的
Stream提供的常用终结方法
方法名说明R collect( Collector collector)把流处理后的结果收集到一个指定的集合中去Object[] toArray()把流处理后的结果收集到一个数组中去
Collector工具类提供了具体的收集方式
方法名说明Public static Collector toList()把元素收集到List集合中去Public static Collector toSet()把元素收集到Set集合中去Public static Collector toMap(Function KeyMapper,Function ValueMapper)把元素收集到Map集合中去