在Java中將數組轉為集合,會用到Arrays.asList()的方法,然而,這個方法卻與我們的預期期望存在一些出入,當用到asList方法將數組轉化成List列表時,對得到的List列表進行add()和remove()操作, JVM會拋出異常:java.lang.UnsupportedOperationException異常
Arrays.asList返回的是同樣的ArrayList,為什么就不能使用add和remove方法呢?
接下來我們來看一下Arrays.asList 源碼
public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }
/** * @serial include */ private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; ArrayList(E[] array) { a = Objects.requireNonNull(array); } @Override public int size() { return a.length; } @Override public Object[] toArray() { return a.clone(); } @Override @SuppressWarnings("unchecked")
AbstractList源碼:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected AbstractList() { } /** * Appends the specified element to the end of this list (optional * operation). * * <p>Lists that support this operation may place limitations on what * elements may be added to this list. In particular, some * lists will refuse to add null elements, and others will impose * restrictions on the type of elements that may be added. List * classes should clearly specify in their documentation any restrictions * on what elements may be added. * * <p>This implementation calls {@code add(size(), e)}. * * <p>Note that this implementation throws an * {@code UnsupportedOperationException} unless * {@link #add(int, Object) add(int, E)} is overridden. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) * @throws UnsupportedOperationException if the {@code add} operation * is not supported by this list * @throws ClassCastException if the class of the specified element * prevents it from being added to this list * @throws NullPointerException if the specified element is null and this * list does not permit null elements * @throws IllegalArgumentException if some property of this element * prevents it from being added to this list */ public boolean add(E e) { add(size(), e); return true; } /** * {@inheritDoc} * * @throws IndexOutOfBoundsException {@inheritDoc} */ abstract public E get(int index); /** * {@inheritDoc} * * <p>This implementation always throws an * {@code UnsupportedOperationException}. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} * * <p>This implementation always throws an * {@code UnsupportedOperationException}. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ 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(); }
由源碼可見,UnsupportedOperationException 是AbstractList拋出的,因為Arrays中的ArrayList並沒有實現remove()和add()方法,所以拋出了異常。
所以說 Arrays.asList 返回的 List 是一個不可變長度的列表,此列表不再具備原 List 的很多特性,因此慎用 Arrays.asList 方法。
ArrayList中構造方法:
ArrayList(E[] array) { a = Objects.requireNonNull(array); }
看一段這樣的代碼:
import java.util.Arrays; import java.util.List; public class Test2{ public static void main(String[] args) { int[] array = new int[]{1,2,3,4,5}; List list = Arrays.asList(array); System.out.println(list.size()); } }
Arrays 的內部類 ArrayList 構造方法接收的是一個泛型數組,即數組類型不能為基本類型,應該為其對應的包裝類型(傳即入引用類型),否則傳入的基本類型的整個數組,將被編譯器視為一個引用參數,
所以原始類型不能作為 Arrays.asList 方法的參數,否則會被當做一個參數
再來看看在Java中將集合轉為數組,ArrayList提供了一個將List轉為數組的一個非常方便的方法toArray。toArray有兩個重載的方法:
@Override public Object[] toArray() { return a.clone(); }
@Override @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { int size = size(); if (a.length < size) return Arrays.copyOf(this.a, size, (Class<? extends T[]>) a.getClass()); System.arraycopy(this.a, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }
對於第一個重載方法,是將list直接轉為Object[] 數組;
第二種方法是將list轉化為你所需要類型的數組,當然我們用的時候會轉化為與list內容相同的類型。
若采用第一種toArray方法,是這樣寫:
1 ArrayList<String> list=new ArrayList<String>(); 2 for (int i = 0; i < 10; i++) { 3 list.add(""+i); 4 } 5 6 String[] array= (String[]) list.toArray();
結果一運行,報錯:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
第一個方法不能將Object[] 轉化為String[],我們需要修改為:
1 Object[] arr = list.toArray(); 2 for (int i = 0; i < arr.length; i++) { 3 String e = (String) arr[i]; 4 System.out.println(e); 5 }
建議用第二種方法:普通數組基本類型必須改為包裝類
import java.util.ArrayList; import java.util.List; public class Test2{ public static void main(String[] args) { List<Integer> list = new ArrayList(); list.add(1); list.add(2); list.add(3); Integer[] array = new Integer[list.size()]; list.toArray(array); for (int i:array){ System.out.print(i+" "); } } }
或者
set.toArray(new Integer[set.size()]);
set好處是去除重復元素