数组与集合都是用来存储对象的容器,前者性质单一,方便易用,后者类型安全,功能强大,且两者之间必然有互相转换的方式。毕竟它们的性格迥异,在转换过程中,如果不注意转换背后的实现方式,很容易产生意料之外的问题。数组转集合和集合转数姐。在数组转集合的过程中,注意是否使用了视图方式直接返回数组中的数据。我们以 Arrays.asList() 为例,它把数组转换成集合时,不能使用其修改集合相关的方法 它的add/remove clear 方法会抛出UnsupportedOperationException 异常。示例源码如下:
package com.wjl.ssmdemo; import java.util.Arrays; import java.util.List; public class ArraysAsList { public static void main(String[] args) { String[] stringArray = new String[3]; stringArray[0] = "one"; stringArray[1] = "two"; stringArray[2] = "three"; List<String> stringList = Arrays.asList(stringArray); //修改转换后的集合,成功地把第一个元素改成“onelist” stringList.set(0,"onelist"); //运行结果是1,数组地值随着改变 System.out.println(stringArray[0]); //编译正确,但是抛出运行时异常 stringList.add("four"); stringList.remove(2); stringList.clear(); } }
Arrays.asList 体现的是适配器模式,后台的数据仍是原有数组, set()方法即间接对数组进行值的修改操作。 asList 的返回对象是一个Arrays的内部类,它并没有实现集合个数的相关修改方法,这也正是抛出异常的原因。Arrays.asList 的源码如下:
public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }
返回的明明是 ArrayList 对象,怎么就不可以随心所欲地对此集合进行修改呢?注意此 ArrayList 非彼 ArrayList ,虽然 Arrays 与ArrayList 同属于一个包,但是在
Arrays 类中还定义了一个 ArrayList 的内部类(或许命名为 InnerArray List 更容易识别),根据作用域就近原则,此处的 ArrayList 是李鬼,即这是个内部类。此李鬼十分简单,只提供了个别方法的实现,如下所示:
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L;
//final修饰不准修改其应用 private final E[] a; ArrayList(E[] array) { a = Objects.requireNonNull(array); } @Override
//实现了修改特定位置元素的方法 public E set(int index, E element) { E oldValue = a[index]; a[index] = element;
//注意set成功返回的是此位置上的旧值。 return oldValue; } }
第一处的 final 引用,用于存储集合的数组引用始终被强制指向原有数组。这个内部类并没有实现任何修改集合元素个数的相关方法 那这个UnsupportedOperatonException 异常是从哪里抛出来的呢?是李鬼的父类AbstractList
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { public void add(int index, E element) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} * * <p>This implementation always throws an * {@code UnsupportedOperationException}. * * @throws UnsupportedOperationException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { throw new UnsupportedOperationException(); } }
如果李鬼 Arrays .ArrayList 内部类写这些方法不抛出异常,避免使用者踩进这个坑会不会更好。数组具有不为五斗米折腰的气节,传递的信息是“要么直接用我,要么小心异常| ”数组转集合引发的故障还是十分常见的。比如,某业务调用某接口时,对方以这样的方式返回 List 类型的集合对象,本方获取集合数据时, 99.9% 是只读操作,但在小概率情况下需要增加一个元素,从而引发故障。在使用数组转集合时,需要使用 java util.ArrayList 直接创建一个新集合,参数就是Arrays .asList 返回的不可变集合,源码如下:
List<Object> objectList = new java.util.ArrayList<Object>(Arrays.asList(数组));
相对于数组转集合来说 集合转数组更加可控,毕竟是从相对自由的集合容器转
为更加苛刻的数组。什么情况下集合需要转成数组呢?适配到人的数组接口,或者进
行局部方法计算等。