10_集合类 list操作的坑

Arrays.asList把数据转换为List的三个坑

1, 不能直接使用Arrays.asList来转换基本类型数
这个List包含的其实是一个int数组,整个List的元素个数是元素类型是整数数组。
int[] arr = {1, 2, 3};
List list = Arrays.asList(arr);   // idea中显示  List<int[]> ints = Arrays.asList(arr);

# 修改  使用包装类型
 Integer[] array = new Integer[]{1,2};
  List<Integer> integers = Arrays.asList(array);
2, Arrays.asList返回的List**不支持增删操作**
,Arrays.asList返回的List并不是我们期望的java.util.ArrayList,**而是Arrays的内部类ArrayList**。ArrayList内部类继承自AbstractList类,并没有覆写父类的add方法,而父类中add方法的实现,就是抛出UnsupportedOperationException。

优化: 声明一个新的List

String[] arr = {"1", "2", "3"};
List list = new ArrayList(Arrays.asList(arr));
3, 使用List.subList进行切片操作居然会导致OOM?
List<Integer> list = IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toList());
List<Integer> subList = list.subList(1, 4);

ArrayList的subList 在list有个内部类, 这个sublist没有创建新的list, 直接用的list。 所以修改sublist和list会相互影响。

解决方法:
1, 不直接使用subList方法返回的SubList,而是重新使用new ArrayList,在构造方法传入SubList,来构建一个独立的ArrayList;
2, 对于Java 8使用Stream的skip和limit API来跳过流中的元素,以及限制流中元素的个数,同样可以达到SubList切片的目的

//方式一:
List<Integer> subList = new ArrayList<>(list.subList(1, 4));
//方式二:
List<Integer> subList = list.stream().skip(1).limit(3).collect(Collectors.toList());

在这里插入图片描述

4,asList 数组与返回的list共享数据
 Integer[] integers = new Integer[3];
        integers[0] = 1;
        integers[1] = 2;
        List<Integer> integers1 = Arrays.asList(integers);
        integers[2] = 3 ;
        Arrays.stream(integers).forEach(System.out::println);
        System.out.println("======>>>>>>");
        integers1.forEach(System.out::println);

在这里插入图片描述

一定要让合适的数据结构做合适的事情

ArrayList和HashMap查找对比

  1. 要对大List进行单值搜索的话,可以考虑
    使用HashMap,其中Key是要搜索的值,Value是原始对象,会比使用ArrayList有非常明显的性能优势。
  2. ArrayList在内存占用上性价比很高,77%(大约)是实际的数据,而HashMap的“含金量”只有22%(大约)。

LinkedList和ArrayList插入和查询对比

  1. 书本上的解释:

    对于数组,随机元素访问的时间复杂度是O(1),元素插入操作是O(n); 查询快
    对于链表,随机元素访问的时间复杂度是O(n),元素插入操作是O(1)。 插入快

  2. 实际: 数组和链表 查询和插入都比链表快。

    插入操作的时间复杂度是O(1)的前提是,你已经有了那个要插入节点的指针。但,在实现的时候,我们需要先通过循环获取到那个节点的Node,然后再执行插入操作。前者也是有开销的,不可能只考虑插入操作本身的代价:
    在这里插入图片描述
    总结:
    1, Arrays.asList得到的是Arrays的内部类ArrayList,List.subList得到的是ArrayList的内部类SubList,不能把这两个内部类转换为ArrayList使用。
    2, Arrays.asList直接使用了原始数组,可以认为是共享“存储”,而且不支持增删元素;List.subList直接引用了原始的List,也可以认为是共享“存储”,而且对原始List直接进行结构性修改会导致SubList出现异常。
    3, 对Arrays.asList和List.subList容易忽略的是,新的List持有了原始数据的引用,可能会导致原始数据也无法GC的问题,最终导致OOM

问题:

  1. 调用类型是Integer的ArrayList的remove方法删除元素,传入一个Integer包装类的数字和传入一个int基本类型的数字,结果一样吗?
  2. 循环遍历List,调用remove方法删除元素,往往会遇到ConcurrentModificationException异常,原因是什么,修复方式又是什么呢?

1、使用 ArrayList 的 remove方法,如果传参是 Integer类型的话,表示的是删除元素,如果传参是int类型的话,表示的是删除相对应索引位置的元素。;两个都需要进行数组拷贝,是通过System.arraycopy进行的
2、以foreach为例说,遍历删除实质是变化为迭代器实现,不管是迭代器里面的remove()还是next()方法,都会checkForComodification();而这个方法是判断modCount和expectedModCount是否相等,这个modCount是这个list集合修改的次数,每一次add或者remove都会增加这个变量,然后迭代器每次去next或者去remove的时候检查checkForComodification();发现expectedModCount(这个迭代器修改的次数)和modCount(这个集合实际修改的次数)不相等,就会抛出ConcurrentModificationException,迭代器里面没有add方法,用迭代器时,可以删除原来集合的元素,但是!一定要
用迭代器的remove方法而不是集合自身的remove方法,否则抛异常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章