• 045天 集合框架09 总结点 问


    0902(045天 集合框架09 总结点 问)

    每日一狗(田园犬西瓜瓜

    在这里插入图片描述

    集合框架09 总结点 问

    1. 问:

    补充:快速失败机制(快死异常)

    多个线程对线程不安全的容器同时进行过操作时会抛出ConcurrentModificationException(并发修改异常)

    原因:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。

    解决办法:

    1. 在遍历过程中,所有涉及到改变modCount值得地方全部加上synchronized。
    2. 使用CopyOnWriteArrayList来替换ArrayList
    3. 或者你也可以接收异常,只有运行正确后才跳出循环

    1.1 问:集合框架一些总结

    常见的集合有哪些

    Map接口和Collection接口是所有集合框架的父接口

    1. Collection接口的子接口包括:Set接口和List接口

    2. Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等(ConcurrentHashMap可以理解为HashMap的线程安全版)

    3. Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等

      HashSet–HashMap TreeSet—TreeMap LinkedHashSet–LinkedHashMap

    4. List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等

      ArrayList–CopyOnWriteArrayList

    集合框架大总结

    在这里插入图片描述

    1、所有集合类都位于java.util包下。Java的集合类主要由两个接口派生而出:Collection和Map,
    Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。

    2、集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。
    Collection List Set Queue Map Comparable Comparator Iterable Iterator

    3、抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。
    AbstractList AbstractSet AbstractMap …

    4、实现类:8个实现类(实线表示),对接口的具体实现。
    ArrayList LinkedList HashSet TreeSet HashMap TreeMap Stack PriorityQueue
    Vector LinkedHashSet Hashtable LinkedHashMap

    5、Collection 接口是一组无序并允许重复的对象。

    6、Set 接口继承 Collection,集合元素无序且不重复。

    7、List接口继承 Collection,允许重复,维护元素插入顺序。

    8、Map接口是键-值对象,与Collection接口没有什么关系。

    9、Set、List和Map可以看做集合的三大类:

    • List集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
    • Set集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集合里元素不允许重复的原因)。
    • Map集合中保存Key-value对形式的元素,访问时只能根据每项元素的key来访问其value。

    10、遍历集合中的对象,Iterable iterator ListIterator[双向遍历]

    特殊的迭代器(走访器)Enumeration属于已经不建议使用的方法

    //@since   1.0
        public interface Enumeration<E>
        Enumeration<Integer> enu = list.elements();
    while(enu.hasMoreElements()) {
        Integer obj=enu.nextElement();
        System.out.println(obj);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    11、看Arrays和Collections。它们是操作数组、集合的两个工具类
    Arrays:排序,折半查找,数组比较,数组深比较,数组展示

    Collections:排序,把一些不安全的容器转换成安全的容器,批量元素替换

    1.2 作业

    1. ArrayList 和 Vector 的区别。

      Vector线程安全 ,ArrayList 线程不安全。

      ArrayList采用延迟初始化,延迟到第一次添加数据的时候

      ArrayList默认扩容比为1.5,Vector有固定的扩容步长,没设定时扩容比为2.0

    2. 说说 ArrayList,Vector, LinkedList 的存储性能和特性。

      ArrayList,Vector的存储都用数组

      LinkedList采用双向链表

      数组访问O(1),增删O(n)

      双向链表访问O(n),增删O(1)

    3. 快速失败 (fail-fast) 和安全失败 (fail-safe) 的区别是什么?

      快速失败:

      安全失败:基于对底层集合进行拷贝

    4. hashmap 的数据结构。

      数组+链表(红黑树)

    5. HashMap 的工作原理是什么?

      HashMap

    6. Hashmap 什么时候进行扩容呢?

      当存储容量到达一定阈值时扩容(最大容积*负载因子)

      当单链>8,总链<64时,也会进行扩容操作

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

      List:可以用对象比较,也可以用索引

      Map:存取使用key值进行定位键值对

      Set:存取使用对象比较方式进行

    8. Set 里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用 == 还是 equals()? 它们有何区别?

      hashCode和equals用的都是HashMap key的判定流程,TreeSet用的是TreeMap,这里用的红黑树,用的是比较器那一套

    9. 两个对象值相同 (x.equals(y) == true),但却可有不同的 hash code,这句话对不对?

      可以,咱们自己封装的自定义数据类型,由于equals和hashCode方法写的不够全面才可能导致这种情况的发生。因为equals是判定两个对象是否相等用的,而hashCode是由另一个方法生成的,不知道咱们计算hashCode值所用属性和equals判定对象相同时所用的属性是否一致,所以这边一般不建议自己写这两个方法,直接用IDE进行生成。

      hash code是以一个对象属性放到散列函数中计算出来的值,但这样想,两个对象的数据一样,但是放到散列函数中计算出来的值却不一样,这咋可能嘛,唯一的可能就是equals和hashCode中用的属性不一样,而且肯定是equals

    10. heap 和 stack 有什么区别。

    2. 流式编程

    多线程针对集合的操作

    Stream不是数据结构,不会存储数据,而是算法的封装。

    操作是并行或并发执行的。

    数据源本身是可以源源不断的

    2.1 概念

    定义

    Stream API借助于同样新出现的Lambda表达式,极大的提高编程效率和程序可读性。

    同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用fork/join并行方式来拆分任务和加速处理过程。

    通常编写并行代码很难而且容易出错, 但使用Stream API无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。

    所以Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。

    元素

    Stream不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的Iterator。

    原始版本的Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如过滤掉长度大于10的字符串、获取每个字符串的首字母等,Stream会隐式地在内部进行遍历,做出相应的数据转换。

    Stream就如同一个迭代器Iterator,单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。

    而和迭代器又不同的是,Stream可以并行化操作,迭代器只能命令式地、串行化操作。
    顾名思义,当使用串行方式去遍历时,每个item读完后再读下一个item。

    而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。

    Stream的并行操作依赖于Java7中引入的Fork/Join框架(JSR166y)来拆分任务和加速处理过程。

    特点

    数据源本身可以是无限的。

    2.2 应用

    当使用一个流的时候,通常包括三个基本步骤:

    获取一个数据源source → 数据转换 → 执行操作获取想要的结果。

    每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道。

    Integer transactionsIds = 
    	roomList.stream()  // 将List转换为stream对象
    		.filter(b -> b.getLength() == 10) // 针对stream种的数据元素进行过滤,只使用为true
    		.sorted((x,y) -> x.getHigh() - y.getHigh()) // 针对stream种的数据进行自定义规则的排序
    		.mapToInt(Room::getWidth)	// 从集合元素通过调用当前对象getWidth方法获取对应的int类型数据
    		.sum();  // 针对整数值进行求和处理
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    使用Stream步骤
    1. 创建Stream;
    2. 转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换)
    3. 对Stream进行聚合(Reduce)操作,获取想要的结果;
    创建Stream方法

    创建方法1:可以使用Arrays.stream()方法来使用Stream

    Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
    long count = Arrays.stream(array)
        .filter(i->i>20)
        .count();
    
    • 1
    • 2
    • 3
    • 4

    创建方法2:使用List创建一个并行流对象Stream

    Stream<Integer> stream = list.parallelStream();
    
    Stream<Integer> stream = list.stream();
    
    • 1
    • 2
    • 3

    创建方法3:Collection.stream()用Java集合都创建一个Stream

    2.3 Stream的一些方法

    • collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的Collectors 提供了非常多收集器,可以说Stream 的核心在于Collectors

    • count 统计操作,统计最终的数据个数

    • findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional

    • noneMatch、allMatch、anyMatch 匹配操作,数据流中是否存在符合条件的元素 返回值为bool 值

    • min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值

    • reduce 规约操作,将整个数据流的值规约为一个值,count、min、max底层就是使用reduce

    • forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了

    • toArray 数组操作,将数据流的元素转换成数组。

    • map(mapToInt,mapToLong,mapToDouble) 转换操作符,把比如A->B,这里默认提供了转int,long,double的操作符

    • flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作,比如把 int[]{2,3,4} 拍平变成 2,3,4 也
      就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符

    • limit 限流操作,比如数据流中有10个只要出前3个就可以使用

    • distint 去重操作,对重复元素去重,底层使用了equals方法

    • filter 过滤操作,把不想要的数据过滤

    • peek 挑出操作,如果想对数据进行某些操作,如:读取、编辑修改等

    • skip 跳过操作,跳过某些元素

    • sorted(unordered) 排序操作,对元素排序,前提是实现Comparable接口,当然也可以自定义比较器。

    扩展小芝士

    • 接口中只定义最基础的东西
    • 对hashSet的元素修改时最好先取出来改完后再放回去,他会重新计算hashCode然后重新定位
    • BigInteger的计算使用一个数组存着然后像手算一样来计算
  • 相关阅读:
    云原生周刊:Argo CD v2.12 发布候选版本 | 2024.06.24
    C语言 -- 动态数组&链表
    趣解设计模式之《小王的糖果售卖机》
    糖葫芦低通滤波器的设计
    HTML5播放 M3U8的hls流地址
    Linux安全配置7小项
    使用cpolar穿透内网
    数仓中的数据对象及相关关系的解读
    Spring Boot 日志的使用
    nc反弹以及中 &>、0>&1是什么意思
  • 原文地址:https://blog.csdn.net/weixin_48015656/article/details/126670769