日常开发中,Arrays工具类十分常用,但如果对Arrays的源码不熟悉的话,就有可能踩到坑。
以下是我日常开发或身边同事遇到关于Arrays工具类的坑:
- 使用Arrays.asList转换为List数组,并对原始的对象修改
- 使用Arrays.asList转换为List数组,并对List数组进行增删改操作
- 使用Arrays.asList转换基本类型对象
踩坑1.使用Arrays.asList转换为List数组,并对原始的对象修改
实例:
public class JavaTestApplication {
public static void main(String[] args) {
// 原始数组对象
String[] strArray = {"H", "e", "l", "l", "o"};
List<String> stringList = Arrays.asList(strArray);
System.out.println(stringList);
strArray[0] = "666";
System.out.println(stringList);
}
}
输出结果:
[H, e, l, l, o]
[666, e, l, l, o]
可以发现,使用Arrays.asList将原来的数组对象转换为list对象后,改变原来的数组对象,list对象也会一同的修改!
深入源码一探究竟!
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
嗯?怎么和我平常使用new ArrayList()创建对象不太一样?比如平常创建ArrayList对象的时候,一般都是通过new ArrayList()
或new ArrayList(Collection c)
,但使用Arrays.asList转换的时候,参数却是一个数组对象,而不是集合类型。莫非是Arrays类的ArrayList对象和java.util.ArrayList不一样?
打开 Arrays.asList 方法中的 ArrayList 对象,居然是Arrays内的内部类!
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
// 直接将参数的数组对象赋值给Arrays.ArrayList的对象
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
// 先省略其他方法
}
通过源码终于知道示例中为什么修改原始的数组会影响转换后的List对象,因为都是共享同一个数组对象呀(也就是说共享同一块内存)!
既然知道问题所在,那就容易解决啦!
public class JavaTestApplication {
public static void main(String[] args) {
String[] strArray = {"H", "e", "l", "l", "o"};
List stringList = new ArrayList(Arrays.asList(strArray));
System.out.println(stringList);
strArray[0] = "666";
System.out.println(stringList);
}
}
输出结果:
[H, e, l, l, o]
[H, e, l, l, o]
结果是达到预想的情况,其实就是通过new一个ArrayList对象,新建一个ArrayList对象的话,就不会共享同一块内存啦!
踩坑2.使用Arrays.asList转换为List数组,并对List数组进行增删改操作
那现在的使用场景,如果我只需要通过Arrays.asList转换为List集合后,对转换后的集合进行增删改操作,那下面的代码会由问题吗?
public class JavaTestApplication {
public static void main(String[] args) {
String[] strArray = {"H", "e", "l", "l", "o"};
List stringList = Arrays.asList(strArray);
System.out.println(stringList);
stringList.add("666");
System.out.println(stringList);
}
}
输出结果:
[H, e, l, l, o]
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at com.muggle.javatest.JavaTestApplication.main(JavaTestApplication.java:12)
哦豁!又有问题!由第一个"坑"可知,asList返回的ArrayList实际上是Arrays的内部类,而内部类ArrayList继承AbstractList抽象类,实际上,示例中的add方法调用的是抽象类AbstractList的add方法,这是一个默认实现方法
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public boolean add(E e) {
add(size(), e);
return true;
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
}
解决的办法其实和上面一样,将asList返回的ArrayList通过new ArrayList()新建一个java.util.ArrayList对象就行了
public class JavaTestApplication {
public static void main(String[] args) {
String[] strArray = {"H", "e", "l", "l", "o"};
List stringList = new ArrayList(Arrays.asList(strArray));
System.out.println(stringList);
stringList.add("666");
System.out.println(stringList);
}
}
踩坑3.使用Arrays.asList转换基本类型对象
如果数组是基本数据类型的呢?使用Arrays.asList会不会有问题?
public class JavaTestApplication {
public static void main(String[] args) {
int[] intArray = {1,2,3,4,5,6};
List<int[]> list = Arrays.asList(intArray);
System.out.println(list);
System.out.println(list.size());
list.stream().forEach(x-> System.out.println(x.getClass()));
}
}
输出结果:
[[I@3feba861]
1
class [I
从输出结果可得知,int[]数组转换为List对象后,长度只有1,类型是整型数组。因此,通过上述的使用是无法将基本数据类型的数组转换为List对象。
有两种办法,第一种方法就是通过将基本类型数组转换为IntStream流再转换为List集合;第二种方法是将基本数据类型改为对应的包装类类型
public class JavaTestApplication {
public static void main(String[] args) {
int[] intArray = {1, 2, 3, 4, 5, 6};
// 方法1:将int数组转换为IntStream流,并且调用boxed方法将stream流内的元素都以整型存在
List<Integer> intStreamList = Arrays.stream(intArray).boxed().collect(Collectors.toList());
intStreamList.stream().forEach(x -> System.out.print(x + " "));
// 方法2:将int数组改为Integer类型
Integer[] integerArray = {1, 2, 3, 4, 5, 6};
List<Integer> integerList = Arrays.asList(integerArray);
integerList.stream().forEach(x -> System.out.print(x + " "));
}
}
以上都是常见的Arrays使用不正确的场景,希望能够诸位在开发的时候,多加注意!
如果觉得文章不错的话,麻烦点个赞哈,你的鼓励就是我的动力!对于文章有哪里不清楚或者有误的地方,欢迎在评论区留言~
参考资料:
极客时间专栏:Java业务开发常见错误100例
网友评论