Java基础入门(六)

第六章 集合

集合可以存储任意类型的对象(对象的引用),并且长度可变。集合类都位于java.util包中。

6.1 集合概述

集合按照其存储结构可以分为单列集合Collection和双列集合Map两大类。

  • Collection:单列集合的根接口,用于存储一系列符合某种规则的元素。它有两个重要的子接口:List和Set。List集合的特点是元素有序、可重复;Set集合的特点是元素无序且不可重复。List接口的主要实现类有ArrayList和LinkedList;Set接口的主要实现类有HashSet和TreeSet。

  • Map:双列集合的根接口,用于存储具有键(Key)、值(Value)映射关系的元素。Map集合中每个元素都包含一对键值,且Key是唯一的,通过指定的Key就能找到对应的Value。

在这里插入图片描述

6.2 Collection接口

是所有单列集合的根接口

Collection接口的主要方法

方法声明功能描述
boolean add(Object o)向集合中添加一个元素
boolean addAll(Collection c)将指定集合c中的所有元素添加到该集合中
void clear()删除该集合中的所有元素
boolean remove(Object o)删除该集合中指定的元素
boolean removeAll(Collection c)删除该集合中包含指定集合c中的所有元素
boolean isEmpty()判断该集合是否为空
boolean contains(Object o)判断该集合中是否包含某个元素
boolean containsAll(Collection c)判断该集合中是否包含指定集合c中的所有元素
Iterator iterator()返回在该集合的元素上进行迭代的迭代器(Iterator),用于遍历该集合所有元素
int size()获取该集合元素的个数
Stream< E > stream()将集合源转换为有序元素的流对象

6.3 List接口

6.3.1 List接口简介

List集合是实现了List接口的对象。在List集合中允许出现重复的元素,所有元素是一种线性方式进行存储的,在程序中可以通过索引(类似于数组中的元素角标)来访问集合中的指定元素。List集合元素有序,即元素的存入顺序和取出顺序一致。

List集合常用方法

方法声明功能描述
void add(int index,Object element)将元素element插入在List集合的指定索引位置
boolean addAll(int index,Collection c)将集合c包含的所有元素插入到List集合的指定索引位置
Object get(int index)返回集合索引index处的元素
Object remove(int index)删除index索引处的元素
Object set(int index,Object element)将索引index处元素替换成element元素,并将替换后的元素返回
int indexOf(Object o)返回对象o在List集合中首次出现的位置索引
int lastIndexOf(Object o)返回对象o在List集合中最后一次出现的位置索引
List subList(int fromIndex,int toIndex)返回从索引fromIndex(包括)到toIndex(不包括)处所有元素集合组成的子集合
Object[] toArray()将集合元素转换为数组
default void sort(Comparator<?super E> c)根据指定的比较器规则对集合元素排序

6.3.2 ArrayList集合

是List接口的一个实现类。可以将其看作一个长度可变的数组。ArrayList内部的数据存储结构是数组形式,在增加和删除指定位置的元素时,会创建新的数组,效率低,因此只有在遍历和查找元素时使用它会非常高效。

为了方便,程序中可以使用“import java.util.*;”来进行导包,其中 * 为通配符,整个语句的意思就是将java.util包中的内容都导入进来。

6.3.3 LinkedList集合

增删元素效率高。

LinkedList集合内部有两个Node类型的first和last属性维护一个双向循环链表,链表中的每一个元素都使用引用的方式来记住它的前一个元素和后一个元素,从而将所有的元素彼此连接起来。

双向列表结构图

在这里插入图片描述

LinkedList中的特有方法

方法声明功能描述
void add(int index,E element)在此列表中指定的位置插入指定的元素
void addFirst(Object o)将指定元素插入集合的开头
void addLast(Object o)将指定元素添加到集合的结尾
Object getFirst()返回集合的第一个元素
Object getLast()返回集合的最后一个元素
Object removeFirst()移除并返回集合的第一个元素
Object removeLast()移除并返回集合的最后一个元素
boolean offer(Object o)将指定元素添加到集合的结尾
boolean offerFirst(Object o)将指定元素添加到集合的开头
boolean offerLast(Object o)将指定元素添加到集合的结尾
Object peek()获取集合的第一个元素
Object peekFirst()获取集合的第一个元素
Object peekLast()获取集合的最后一个元素
Object poll()移除并返回集合的第一个元素
Object pollFirst()移除并返回集合的第一个元素
Object pollLast()移除并返回集合的最后一个元素
void push(Object o)将指定元素添加到集合的开头
Object pop()移除并返回集合的第一个元素

6.4 Collection集合遍历

6.4.1 Iterator遍历集合

Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Interator对象也被称为迭代器。

6.4.2 foreach遍历集合

foreach循环是一种更加简洁的for循环,也称为增强for循环。用于遍历数组或集合中的元素。具体语法格式如下:

for(容器中元素类型 临时变量 : 容器变量) {

		//执行语句

}
  1. 使用foreach循环遍历集合和数组时,只能访问集合中的元素,不能对其中的元素进行修改。

  2. 使用Interator迭代器对集合中的元素进行迭代时,如果调用了集合对象的remove方法去删除元素,会出现异常

    解决

    ​ 从业务逻辑上讲只想将某个元素删除,至于后面还有多少元素我们并不关心,所以只需找到该元素后跳出循环不再迭代即可,即增加一个break语句

    ​ 如果需要在集合的迭代期间对集合中的元素进行删除,可以使用迭代器本身的删除方法,即使用it.remove()

6.4.3 JDK8的forEach遍历集合(函数式接口)

在JDK8中,所有集合对象都可以使用forEach(Consumer action)方法来遍历集合。而且,Iterator迭代器对象可以使用forEachRemaining(Consumer action)方法来进行遍历。

6.5 Set接口

6.5.1 Set接口简介

Set接口中的元素无序且不重复。它主要有两个实现类HashSet(根据对象的哈希值来确定元素在集合中的存储位置)和TreeSet(是以二叉树的方式来存储元素,它可以实现对集合中的元素进行排序)。

6.5.2 HashSet集合

当向HashSet集合中添加一个元素时,首先会调用该元素的hashCode()方法来确定元素的存储位置,然后再调用元素对象的equals()方法来确保该位置没有重复元素。

图片

6.5.3 TreeSet集合

内部采用平衡二叉树来存储元素,这样的结构可以保证TreeSet集合中没有重复的元素且可以对元素进行排序。所谓二叉树就是每个节点最多有两个子节点的有序树,每个节点及其子节点组成的树称为子树。左子树上的元素小于它的根结点,而右子树上的元素大于它的根结点。

在这里插入图片描述

同一层的元素,左边的元素总是小于右边的元素。

TreeSet集合的特有方法

方法声明功能描述
Object first()返回TreeSet集合的首个元素
Object last()返回TreeSet集合的最后一个元素
Object lower(Object o)返回TreeSet集合中小于给定元素的最大元素,如果没有返回null
Object floor(Object o)返回TreeSet集合中小于或等于给定元素的最大元素,如果没有返回null
Object higher(Object o)返回TreeSet集合中大于给定元素的最小元素,如果没有返回null
Object ceiling(Object o)返回TreeSet集合中大于或等于给定元素的最小元素,如果没有返回null
Object pollFirst()移除并返回集合的第一个元素
Object pollLast()移除并返回集合的最后一个元素

集合中的元素在进行比较时,都会调用compareTo()方法,该方法是Comparable接口中定义的,要想对集合中的元素进行排序,就必须实现Comparable接口。

自定义类型的数据没有实现Comparable接口,无法直接在TreeSet集合中进行排序操作,因此提供了两种排序规则:自然排序和定制排序。默认情况下是采用自然排序。

  • 自然排序

要求向TreeSet集合中存储的元素所在类必须实现Comparable接口,并重写compareTo()方法,然后调用该方法默认进行升序排序。

  • 定制排序

在创建TreeSet集合时就自定义一个比较器来对元素进行定制排序。

6.6 Map接口

6.6.1 Map接口简介

Map接口是一种双列集合,它的每个元素都包含一个键对象Key和值对象Value,键和值对象之间存在一种对应关系,称为映射。Map中的映射关系是一对一的,一个键对象Key对应唯一一个值对象Value,其中键对象Key和值对象Value可以是任意数据类型,并且键对象Key不允许重复。

Map集合常用方法

方法声明功能描述
void put(Object key,Object value)向MAp集合中添加指定键值映射的元素
int size()返回Map集合键值对映射的个数
Object get(Object key)返回指定键所映射的值,如果此映射不包含该键的映射关系,则返回null
boolean containsKey(Object key)查看Map集合中是否存在指定的键对象key
boolean containsValue(Object value)查看Map集合中是否存在指定的值对象value
Object remove(Object key)删除并返回Map集合中指定键对象Key的键值映射元素
void clear()清空整个Map集合中的键值映射元素
Set keySet()以Set集合的形式返回Map集合中所有的键对象Key
Collection values()以Collection集合的形式返回Map集合中所有的值对象Value
Set<Map.Entry<Key,Value>> entrySet()将Map集合转换为存储元素类型为Map的Set元素
Object getOrDefault(Object key,Object default Value)返回Map集合指定键所映射的值,如果不存在则返回默认值defaultValue(JDK8较之前版本增加的方法)
void forEach(BiConsumer action)通过传入一个函数式接口对Map集合元素进行遍历(JDK8较之前版本增加的方法)
Object putIfAbsent(Object key,Object value)向Map集合中添加指定键值映射的元素,如果集合中已存在的值对象Value(JDK8较之前版本增加的方法)
boolean remove(Object key,Object value)删除Map集合中键值映射同时匹配的元素(JDK8较之前版本增加的方法)
boolean replace(Object key,Object value)将Map集合中指定键对象Key所映射的值修改为value(JDK8较之前版本增加的方法)

6.6.2 HashMap集合

HashMap底层是由哈希表结构组成的,其实就是"数组+链表"的组合体,数组是HashMap的主体结构,链表则是为了解决哈希值冲突而存在的分支结构。
水平方向以数组结构为主体并在竖直方向以链表结构进行结合的就是HashMap中的哈希表结构。
在哈希表结构中,水平方向数组的长度称为HashMap集合的容量,竖直方向每个元素位置对应的链表结构称为一个桶(bucket)。
每个桶的位置都有对应的桶值,用于快速定位集合元素添加、查找时的位置。
在这里插入图片描述

从查找性能上说,HashMap中的链表出现越少,性能才会越好,即桶越多越好。

6.6.3 Map集合遍历

  1. Iterator 迭代器遍历 Map 集合

    1. KeySet()

      将Map集合中所有键对象转换为Set单列集合,接着将包含键对象的Set集合转换为Iterator接口对象,然后遍历Map集合中所有的键,再根据键获取相应的值。

    2. entrySet()

      将原有Map集合中的键值作为一个整体返回为Set集合,接着将包含键值对对象的Set集合转换为Iterator接口对象,然后获取集合中的所有键值对映射关系,再从映射关系中取出键和值。

  2. 使用 forEach(BiConsumer action) 方法遍历 Map 集合

  3. values()

    可以直接获取Map中存储所有值的Collection集合。

使用LinkedHashMap 集合保证元素添加顺序

6.6.4 TreeMap集合

TreeMap内部是通过二叉树的原理来保证键的唯一性。

6.6.5 Properties集合

Hashtable与HashMap十分相似,但Hashtable是线程安全的,效率不及HashMap,因此被取代。Properties集合是其子类,在实际应用开发中很重要。它主要用来存储字符串类型的键和值,存取应用的配置项。

6.7 泛型

引出:集合可以存储任意类型的对象元素,但当把一个对象存入集合后,就会被集合“忘记”它的类型,那么在取出时无法知道其原本类型,强转时容易出错。

泛型:可以限定操作的数据类型,在定义集合类时,可以使用<参数化类型>的方式指定该集合中存储的数据类型,具体格式如下:

ArrayList<参数化类型> list = new ArrayList<参数化类型>();

6.8 常用工具类

6.8.1 Collections工具类

  1. 添加、排序操作

    方法声明功能描述
    static boolean addAll(Collection<?super T> c,T… elements)将所有指定元素添加到指定集合 c 中
    static void reverse(List list)反转指定 List 集合中元素的顺序
    static void shuffle(List list)对 List 集合中的元素进行随机排序
    static void sort(List list)根据元素的自然顺序对 List 集合中的元素进行排序
    static void swap(List list,int i,int j)将指定 List 集合中角标 i 处元素和 j 处元素进行交换
  2. 查找、替换操作

    方法声明功能描述
    static int binarySearch(List list,Object key)使用二分法搜索指定对象在 List 集合中的索引,查找的 List 集合中的元素必须是有序的
    static Object max(Collection col)根据元素的自然顺序,返回给定集合中最大的元素
    static Object min(Collection col)根据元素的自然顺序,返回给定集合中最小的元素
    static boolean replaceAll(List list,Object oldVal,Object newVal)用一个新值 newVal 替换 List 集合中所有的旧值 oldVal

6.8.2 Arrays工具类

  1. 使用 sort() 方法排序

    会按照自然顺序(即从小到大)对数组元素进行排序。Arrays类还有许多重载的 sort() 方法,来按不同的规则进行排序。

  2. 使用 binarySearch(Object[] a,Object key) 方法查找元素

    它只能针对排序后的数组进行元素查找。
    【补充二分法查找】

    假设start、end和mid[mid=(start+end)/2]分别代表在数组中
    查找区间的开始索引、结束索引和中间索引,假设查找的元素为key。
    

在这里插入图片描述

	1. 判断开始索引start和结束索引end,
		如果start<=end,则key和arr[mid]进行比较;
		如果两者相等,说明找到了该元素;
		如果不相等,则需要进入第二步继续比较二者的大小。
	2. 将key和arr[mid]继续进行比较,
		如果key<arr[mid],表示查找的值处于索引start和mid之间,
		这时执行第三步,否则表示要查找的值处于索引mid和end之间,
		这时执行第四步。
	3. 将查找区间的结束索引end置为mid-1,开始索引不变,
		中间索引mid重新置为(start+end)/2,继续查找,直到start>end,
		表示查找的数组不存在,这时执行第五步。
	4. 将查找区间的开始索引start置为mid+1,结束索引不变,
		中间索引mid重新置为(start+end)/2,继续查找,直到start>end,
		表示查找的数组不存在,这时执行第五步。
	5. 返回“(插入点)-(start+1)”。这个“插入点”指的是
		大于key值的第一个元素在数组中的位置,如果数组中所有的元素
		值都要小于要查找的对象,“插入点”就等于“Array.length”。
  1. 使用 copyOfRange(int[] original,int from,int to) 方法拷贝元素

  2. 使用 fill(Object[] a,Object val) 方法替换元素
    将指定的值赋给数组中的每一个元素。

6.9 聚合操作

6.9.1 聚合操作简介

步骤:

  1. 将原始集合或者数组对象转换为 Stream 流对象;
  2. 对 Stream 流对象中的元素进行一系列的过滤、查找等中间操作(Intermediate Operations),然后仍然返回一个 Stream 流对象;
  3. 对 Stream 流进行遍历、统计、收集等终结操作(Terminal Operations),获取想要的结果。

注意:

  1. 将执行某个方法后返回类型仍为 Stream 流对象中的方法归类为中间操作,如过滤、截取、排序等方法;而将执行方法后返回类型不再是 Stream 流对象的方法归类为终结操作,如遍历、统计、收集等方法。
  2. 在进行聚合操作时,只是改变了 Stream 流对象中的数据,并不会改变原始集合或数据中的源数据。

6.9.2 创建Stream流对象

创建 Stream 流对象的方式:

  1. 所有的 Collections 集合都可以使用 stream() 静态方法获取 Stream 流对象;
  2. Stream 接口的 of() 静态方法可以获取基本类型包装类数组、引用类型数组和单个元素的 Stream 流对象;
  3. Arrays 数组工具类的 stream() 静态方法也可以获取数组元素的 Stream 流 对象。

6.9.3 Stream流的常用方法

方法声明功能描述
Stream< T > filter(Predicate<? super T> predicate)将指定流对象中的元素进行过滤,并返回一个子流对象
Stream< R > map(Function<? super T,? extends R> mapper)将流中的元素按规则映射到另一个流中
Stream< T > distinct()删除流中重复的元素
Stream< T > sorted()将流中的元素按自然顺序排序
Stream< T > limit(long maxSize)截取流中元素的长度
Stream< T > skip(long n)丢弃流中前n个元素
static< T > Stream< T > concat(Stream<? extends T > a,Stream<? extends T > b)将两个流对象合并为一个流
long count()统计流中元素的个数
R collect(Collector<? super T,A,R> collector)将流中的元素收集到一个容器中(如集合)
Object[] toArray()将流中的元素收集到一个数组中
void forEach(Consumer<? super T> action)将流中的元素进行遍历

注意: 一个Stream流对象可以连续进行多次中间操作,仍会返回一个流对象,但一个流对象只能进行一次终结操作,并且一旦进行终结操作后,该流对象就不复存在了。

6.9.4 Parallel Stream(并行流)

串行流 就是将源数据转换为一个流对象,然后在单线程下执行聚合操作的流(也是单一管道流);
并行流 则是将源数据分为多个子流对象进行多线程操作(也就是多个管道流),然后再将处理的结果再汇总为一个流对象。

为了能够在聚合操作中使用Stream并行流,前提是要执行操作的源数据在并行执行过程中不会被修改。

JDK 8 中创建Stream并行流的两种方式:

  1. 通过Collection集合接口的parallelStream()方法直接将集合类型的源数据转变为Stream并行流;
  2. 通过BaseStream接口的parallel()方法将Stream串行流转变为Stream并行流。此外,该接口中还有一个isParallel()方法,用于判断当前Stream流对象是否为并行流,方法返回值为boolean类型。

小结:第六章很艰难,可能是我自己没有吃透,这篇文花了太多时间(作图也好费时间【抓狂】),效率实在是太低了,各位见谅 = 。=

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值