嗨~大家周末愉快啊,我是阿壮,一个 Java 程序员,最近在工作之余,即没 bug 要改了,也没需求了,又不能让老板看到自己在摸鱼,无聊的我开始 ctrl+鼠标左键,漫无目的的看着眼前的 JDK 源码。今天来更大家分享以下我遇到过的java.util.Arrays
下的坑。
主要分析三个问题,并给出对于的解决方案
- 通过 asList 返回的固定大侠的 List 不支持添加元素
- 对原始数组的修改会影响到我们获得的那个 List
- 不能直接使用 Arrays.asList 来转换基本类型数组
请允许我使用巨佬 Java 之父 James Gosling 写的JDK源码作为今天的开始。
通过 asList 返回的固定大侠的 List 不支持添加元素
代码
public static void main(String[] args) {
String[] arr = new String[]{"aa", "bb"};
List list = Arrays.asList(arr);
list.add("cc");
}
执行结果
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at Test.main(Test.java:8)
原因是 java.util.Arrays.ArrayList 类实现了 set(), get(),contains()方法,但是并没有实现增加元素的方法(事实上是可以调用 add 方法,但是没有具体实现,仅仅抛出 UnsupportedOperationException 异常),因此它的大小也是固定不变的。可以通过 set 方法进行设置值,默认长度是 10。
解决方案
新建一个 ArrayList
代码:
public static void main(String[] args) {
String[] arr = {"aa", "bb", "cc"};
List list = Arrays.asList(arr);
ArrayList strings = new ArrayList<>(list);
strings.add("dd");
System.out.println(strings.toString());
}
执行结果:
[aa, bb, cc, dd]
通过集合工具类 Collections.addAll()方法(最高效,推荐)
通过 Collections.addAll(arrayList, strArray)方式转换,根据数组的长度创建一个长度相同的 List,然后通过 Collections.addAll()方法,将数组中的元素转为二进制,然后添加到 List 中,这是最高效的方法。
代码:
public static void main(String[] args) {
String[] arr = {"aa", "bb", "cc"};
ArrayList strings = new ArrayList<>(arr.length);
Collections.addAll(strings, arr);
strings.add("dd");
System.out.println(strings.toString());
}
执行结果:
[aa, bb, cc, dd]
Stream 优雅的写法
代码:
public static void main(String[] args) {
String[] arr = {"aa", "bb", "cc"};
List list = Stream.of(arr).collect(Collectors.toList());
list.add("dd");
System.out.println(list.toString());
}
执行效果:
[aa, bb, cc, dd]
底层先将数组转换为流,再使用 addAll()的方式,执行效率次于Collections.addAll()
方式,但是写法优雅呀。
对原始数组的修改会影响到我们获得的那个 List
代码
public static void main(String[] args) {
String[] arr = {"aa", "bb", "cc"};
List list = Arrays.asList(arr);
arr[1] = "dd";
System.out.printf("arr:%s list:%s", Arrays.toString(arr), list);
}
执行结果
arr:[aa, dd, cc] list:[aa, dd, cc]
原因是 Arrays 内部类 ArrayList 其实是直接使用了原始的数组,把通过 Arrays.asList 获得的 List 交给其他方法处理,很容易因为共享了数组,相互修改产生 Bug。
不能直接使用 Arrays.asList 来转换基本类型数组
代码
public static void main(String[] args) {
int[] arr = {1, 2, 3};
List list = Arrays.asList(arr);
System.out.println(list.size());
}
执行结果
1
原因是 asList 方法的参数必须是对象或者对象数组,而原生数据类型不是对象,当传入一个原生数据类型数组时,asList 的真正得到的参数就不是数组中的元素,而是数组对象本身。
解决方案
Java8 可通过 stream 流将 3 种基本类型数组转为 List
如果 JDK 版本在 1.8 以上,可以使用流 stream 来将下列 3 种数组快速转为List
,分别是int[]
、long[]
、double[]
,其他数据类型比如short[]
、byte[]
、char[]
,在 JDK1.8 中暂不支持。
代码:
public static void main(String[] args) {
int[] arr = {1, 2, 3};
List list = Arrays.stream(arr).boxed().collect(Collectors.toList());
System.out.println(list);
}
执行效果:
[1, 2, 3]
我是阿壮,一个后端程序员,微信搜一搜:科技猫,持续分享原创编程技术,实用软件,科技资讯,我们下期间