首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >java业务开发常见错误100例list笔记

java业务开发常见错误100例list笔记

原创
作者头像
IT工作者
发布2022-05-05 16:13:55
发布2022-05-05 16:13:55
5530
举报
文章被收录于专栏:程序技术知识程序技术知识

使用 List.subList 进行切片操作居然会导致 OOM?

代码语言:javascript
复制
private static List<List<Integer>> data = new ArrayList<>();
private static void oom() {
    for (int i = 0; i < 1000; i++) {
  List<Integer> rawList = IntStream.rangeClosed(1, 100000).boxed().collect(Collectors.toList());
  data.add(rawList.subList(0, 1));
    }
}

删除子 List 中的元素影响到了原始 List;尝试为原始 List 增加数字 0 之后再遍历子 List,会出现

ConcurrentModificationException。

代码语言:javascript
复制

List<Integer> list = IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toList());
List<Integer> subList = list.subList(1, 4);
System.out.println(subList);
subList.remove(1);
System.out.println(list);
list.add(0);
try {
    subList.forEach(System.out::println);
} catch (Exception ex) {
    ex.printStackTrace();
}

既然 SubList 相当于原始 List 的视图,那么避免相互影响的修复方式有两种: 修复后代码输出如下: 一种是,不直接使用 subList 方法返回的 SubList,而是重新使用 new ArrayList,在构 造方法传入 SubList,来构建一个独立的 ArrayList; 另一种是,对于 Java 8 使用 Stream 的 skip 和 limit API 来跳过流中的元素,以及限制 流中元素的个数,同样可以达到 SubList 切片的目的。  //方式一: List subList = new ArrayList<>(list.subList(1, 4));

//方式二:

List<Integer> collect = list.stream().skip(1).limit(4).collect(Collectors.toList());

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

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

随机 插入操作居然也是 LinkedList 落败,耗时 9.3 秒,ArrayList 只要 1.5 秒:抛开算法层面不谈,由于 CPU 缓存、内存连续性等问题,链表这种数 据结构的实现方式对性能并不友好,即使在它最擅长的场景都不一定可以发挥威力。

代码语言:javascript
复制
int elementCount = 100000;
int loopCount = 100000;
StopWatch stopWatch = new StopWatch();
stopWatch.start("linkedListGet");
linkedListGet(elementCount, loopCount);
stopWatch.stop();
stopWatch.start("arrayListGet");
arrayListGet(elementCount, loopCount);
stopWatch.stop();
System.out.println(stopWatch.prettyPrint());

StopWatch stopWatch2 = new StopWatch();
stopWatch2.start("linkedListAdd");
linkedListAdd(elementCount, loopCount);
stopWatch2.stop();
stopWatch2.start("arrayListAdd");
arrayListAdd(elementCount, loopCount);
stopWatch2.stop();
System.out.println(stopWatch2.prettyPrint());
//LinkedList访问
private static void linkedListGet(int elementCount, int loopCount) {
    List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed()
    .collect(Collectors.toCollection(LinkedList::new));
    IntStream.rangeClosed(1, loopCount).forEach(i -> list.get(ThreadLocalRandom.current()
    .nextInt(elementCount)));
}
//ArrayList访问
private static void arrayListGet(int elementCount, int loopCount) {
    List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed()
    .collect(Collectors.toCollection(ArrayList::new));
    IntStream.rangeClosed(1, loopCount).forEach(i -> list.get(ThreadLocalRandom.current()
    .nextInt(elementCount)));
}
//LinkedList插入
private static void linkedListAdd(int elementCount, int loopCount) {
    List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed()
    .collect(Collectors.toCollection(LinkedList::new));
    IntStream.rangeClosed(1, loopCount).forEach(i -> list.add(ThreadLocalRandom.current()
    .nextInt(elementCount)));
}
//ArrayList插入
private static void arrayListAdd(int elementCount, int loopCount) {
    List<Integer> list = IntStream.rangeClosed(1, elementCount).boxed()
    .collect(Collectors.toCollection(ArrayList::new));
    IntStream.rangeClosed(1, loopCount).forEach(i -> list.add(ThreadLocalRandom.current()
    .nextInt(elementCount)));
}

调用类型是 Integer 的 ArrayList 的 remove 方法删除元素,传入一个 Integer 包装类 的数字和传入一个 int 基本类型的数字,结果一样吗?

代码语言:javascript
复制
List<Integer> list = IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toList());
Collections.shuffle(list);
System.out.println(list);
list.remove(1);
System.out.println(list);
list.remove(Integer.valueOf(1));
System.out.println(list);

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档