将数组转换为ArrayList:为何这是Java开发者的永恒痛点
每个写过Java代码的人,都曾遇到过这种情况:你有一个现成的数组 String[] 或 int[],但任务需要的是一个灵活的 ArrayList,它拥有 add()、remove() 方法和动态大小。看似小事,但正是这个问题在Stack Overflow上获得了数万次浏览和大量点赞。为什么?因为就像Java中常见的情况一样,有一个“显而易见”的解决方案,却暗藏陷阱。
在本文中,我们不仅会提供现成的代码。我们将逐一介绍在Java中从数组创建ArrayList的所有方法,分析它们的优缺点、性能,最重要的是——何时使用哪种方案。阅读后,您将能够自信地为自己的任务选择正确的工具,而不会在最意想不到的时刻遇到 UnsupportedOperationException。
开始吧!(或者像Java开发者说的——let's dive into the code)
方法1:经典方式——Arrays.asList()
最流行且最简短的方法。您可能已经见过它:
String[] fruits = {"apple", "banana", "cherry"};List<String> fruitList = Arrays.asList(fruits);看起来不错,对吧?但有一个问题。方法 Arrays.asList() 返回的不是 java.util.ArrayList,而是其内部的静态版本——java.util.Arrays.ArrayList。这是一个固定大小的列表,不支持调整大小的操作。如果您尝试执行 fruitList.add("date"),将会得到 UnsupportedOperationException。
优点:
- 代码极其简短且可读性强。
- 可作为数组与集合API之间的桥梁。
- 对列表的修改会反映到原始数组上(反之亦然)。
缺点:
- 固定大小——无法添加或删除元素。
- 返回的列表是数组的“包装器”,而非完整的ArrayList。
何时使用:当您只需要一个只读列表,或者您确定大小不会改变时。例如,将其传递给接受 List<?> 且不会修改它的方法。
如何从Arrays.asList()获得完整的ArrayList?
只需将结果包装在构造函数中:
String[] fruits = {"apple", "banana", "cherry"};ArrayList<String> fruitList = new ArrayList<>(Arrays.asList(fruits));fruitList.add("date"); // 现在可以正常工作,没有错误这个技巧是两全其美的方法。您使用了 Arrays.asList 的简洁写法,但获得了完整的动态集合。
方法2:Collections.addAll()——速度与控制
如果您追求性能,或者只是想避免双重复制(先复制到固定大小的列表,再复制到ArrayList),可以使用 Collections.addAll() 方法:
String[] fruits = {"apple", "banana", "cherry"};ArrayList<String> fruitList = new ArrayList<>(fruits.length);Collections.addAll(fruitList, fruits);这里发生了什么?我们直接创建了一个具有所需初始容量的 ArrayList(以避免内部数组不必要的重建),然后一次性复制所有元素。方法 addAll 比 for 循环更快,因为它在底层调用了 System.arraycopy()。
优点:
- 速度快——几乎达到直接内存复制的水平。
- 直接获得一个完整的、可修改的ArrayList。
- 可以预先指定列表的容量。
缺点:
- 代码稍