一篇文章带你了解 asList数组转换List有哪些坑?

在使用 Arrays.asList() 将数组转换为 List 时,有一些常见的坑需要注意:

1. 返回的 List 是固定大小

Arrays.asList() 返回的并不是 java.util.ArrayList,而是一个固定大小的 List,它的底层是一个数组。由于这个 List 是基于原始数组的视图,因此不能增加或删除元素,但可以修改元素。

示例:
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);

list.add("D"); // 抛出 UnsupportedOperationException
list.remove(0); // 抛出 UnsupportedOperationException
list.set(1, "E"); // 允许修改

2. 原始数组和 List 共享同一块内存

使用 Arrays.asList() 返回的 List 仍然依赖于原始的数组,修改 List 中的元素会反映在原始数组中,反之亦然。

示例: 
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);

list.set(1, "E");
System.out.println(Arrays.toString(array)); // 输出: [A, E, C]

array[0] = "X";
System.out.println(list); // 输出: [X, E, C]

3. 对基本类型数组的处理

如果你传递一个基本数据类型的数组(例如 int[])给 Arrays.asList(),它会把整个数组当作一个单独的元素,而不是将数组中的每个元素作为 List 的元素。

示例:
int[] intArray = {1, 2, 3};
List<int[]> list = Arrays.asList(intArray);

System.out.println(list.size()); // 输出: 1
System.out.println(list.get(0));  // 输出: [I@15db9742

坑点:返回的 List 只有一个元素,它是整个 int[] 数组,而不是 [1, 2, 3] 这三个元素。

解决方案:

如果你需要一个可以修改大小的 List,或者不想让数组和 List 共享数据,你可以这样做:

  • 使用 new ArrayList<>(Arrays.asList(array)):创建一个新的 ArrayList 实例,它是可变的并且不依赖于原始数组。

    String[] array = {"A", "B", "C"};
    List<String> list = new ArrayList<>(Arrays.asList(array));
    
    list.add("D"); // 成功
    
  • 对于基本类型数组,使用 Stream API 转换:

    int[] intArray = {1, 2, 3};
    List<Integer> list = Arrays.stream(intArray).boxed().collect(Collectors.toList());
    

4. 对集合操作的误解

很多开发者在使用 Arrays.asList() 时期望返回的是一个完整的 java.util.List 实现,但其实它返回的是 java.util.Arrays.ArrayList,这是一个内部静态类,并不是 java.util.ArrayList。因此,它缺乏一些常用的 List 操作方法。

示例:
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);

if (list instanceof ArrayList) {
    System.out.println("This is a java.util.ArrayList"); // 不会输出
} else {
    System.out.println("This is not a java.util.ArrayList"); // 会输出
}

坑点Arrays.asList() 返回的是 Arrays.ArrayList,与 java.util.ArrayList 是不同的类。Arrays.ArrayList 继承自 AbstractList,因此它是固定大小的,不支持修改集合大小的操作(如 add()remove())。

5. 泛型类型推断问题

当你将数组传入 Arrays.asList() 时,如果没有明确指定数组类型,可能会引发泛型推断问题,导致不可预期的结果。

示例:
Object[] array = {"A", "B", 1}; // 混合类型数组
List<Object> list = Arrays.asList(array); // 正常工作

Object[] array2 = {1, 2, 3};
List<Object> list2 = Arrays.asList(array2); // 工作正常,但有时类型推断会失败

坑点Arrays.asList() 将多维数组看作是一个元素数组,并不会展开为 List<List<T>> 的形式。因此需要自己进行手动处理,如果想要一个嵌套的 List 结构,可以使用流或其他方式转换。

7. 线程安全性

Arrays.asList() 返回的 List 不是线程安全的。如果在多线程环境下修改这个列表,可能会引发并发问题。

解决方案:

如果需要线程安全的 List,可以使用 Collections.synchronizedList() 包装返回的 List

String[] array = {"A", "B", "C"};
List<String> list = Collections.synchronizedList(Arrays.asList(array));

但即使这样,这个 List 仍然是固定大小的,无法增加或删除元素。如果需要一个线程安全且可变大小的 List,你需要创建一个新的 ArrayList

List<String> list = new ArrayList<>(Arrays.asList(array));
List<String> synchronizedList = Collections.synchronizedList(list);

8. 并行流问题

在使用 Arrays.asList() 生成的 List 进行并行流操作时,由于其底层是基于数组的,某些操作可能会有意外的表现,尤其是涉及到并行修改或扩展大小的场景。因为返回的 List 是固定大小的,它在某些并行操作中会失效,特别是涉及到元素的 addremove 时。

示例:
String[] array = {"A", "B", "C"};
List<String> list = Arrays.asList(array);

// 使用并行流进行修改
list.parallelStream().forEach(s -> {
    // 这里对list的结构性修改可能会导致问题
    if ("A".equals(s)) {
        list.add("D"); // 抛出 UnsupportedOperationException
    }
});

总结:

使用 Arrays.asList() 的过程中,需要小心以下几点:

  • 它返回的 List 是固定大小的,不能进行 add()remove() 操作。
  • 原始数组和返回的 List 共享数据,修改一个会影响另一个。
  • 对基本类型或多维数组的处理可能不符合预期,通常会返回单个元素数组。
  • 泛型类型推断可能会导致不一致或编译错误。
  • 并发操作需要格外小心,尤其是并行流中不能进行结构性修改。

通过理解这些潜在的陷阱,可以避免在使用 Arrays.asList() 时踩坑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大大怪~将军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值