Arrays.asList()使用指南

2021-01-14 15:02:01 浏览数 (1)

概述

该方法是将数组转化成List集合的方法。

List<String> list = Arrays.asList("a","b","c");

注意:

  • 该方法适用于对象型数据的数组(String、Integer...)。
  • 该方法不建议使用于基本数据类型的数组(byte,short,int,long,float,double,boolean)。
  • 该方法将数组与List列表链接起来:当更新其一个时,另一个自动更新。
  • 不支持add()、remove()、clear()等方法。

Arrays.asList()是个坑

用此方法得到的List的长度是不可改变的,

当你向这个List添加或删除一个元素时(例如 list.add("d");)程序就会抛出异常(java.lang.UnsupportedOperationException)。怎么会这样?只需要看看asList()方法是怎么实现的就行了:

public static <T> List<T> asList(T... a) {return new ArrayList<>(a);}

当你看到这段代码时可能觉得没啥问题啊,不就是返回了一个ArrayList对象吗?问题就出在这里。

这个ArrayList不是java.util包下的,而是java.util.Arrays.ArrayList

它是Arrays类自己定义的一个静态内部类,这个内部类没有实现add()、remove()方法,而是直接使用它的父类AbstractList的相应方法。

而AbstractList中的add()和remove()是直接抛出java.lang.UnsupportedOperationException异常的!

代码语言:javascript复制
public void add(int index, E element) { throw new UnsupportedOperationException();}

public E remove(int index) {throw new UnsupportedOperationException();}

案例

Arrays.asList()在平时开发中还是比较常见的,我们可以使用它将一个数组转换为一个List集合。

代码语言:javascript复制
String[] myArray = {"Apple", "Banana", "Orange"};
List<String> myList = Arrays.asList(myArray);
//上面两个语句等价于下面一条语句
List<String> myList = Arrays.asList("Apple","Banana", "Orange");

JDK 源码对于这个方法的说明:

代码语言:javascript复制
/**
  *返回由指定数组支持的固定大小的列表。此方法作为基于数组和基于集合的API之间的桥梁,
  * 与 Collection.toArray()结合使用。返回的List是可序列化并实现RandomAccess接口。
  */
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

使用时的注意事项总结

传递的数组必须是对象数组,而不是基本类型。

Arrays.asList()是泛型方法,传入的对象必须是对象数组。

代码语言:javascript复制
  public static void main(String[] args) {
      int[] myArray = {1, 2, 3};
      List myList = Arrays.asList(myArray);
      //1
      System.out.println(myList.size());
      //数组地址值
      System.out.println(myList.get(0));
      //报错:ArrayIndexOutOfBoundsException
//        System.out.println(myList.get(1));
      int[] array = (int[]) myList.get(0);
      System.out.println(array[0]);//1
  }

当传入一个原生数据类型数组时,Arrays.asList() 真正得到的参数就不是数组中的元素,而是数组对象本身!此时List 的唯一元素就是这个数组,这也就解释了上面的代码。

我们使用包装类型数组就可以解决这个问题。

代码语言:javascript复制
  public static void main(String[] args) {
      int[] myArray = {1, 2, 3};
      List myList = Arrays.asList(myArray);
      //1
      System.out.println(myList.size());
      //数组地址值
      System.out.println(myList.get(0));
  }

使用集合的修改方法:add()remove()clear()会抛出异常。

代码语言:javascript复制
List myList = Arrays.asList(1, 2, 3);
myList.add(4);//运行时报错:UnsupportedOperationException
myList.remove(1);//运行时报错:UnsupportedOperationException
myList.clear();//运行时报错:UnsupportedOperationException

Arrays.asList() 方法返回的并不是 java.util.ArrayList ,而是 java.util.Arrays 的一个内部类,这个内部类并没有实现集合的修改方法或者说并没有重写这些方法。

代码语言:javascript复制
List myList = Arrays.asList(1, 2, 3);
System.out.println(myList.getClass());//class java.util.Arrays$ArrayList

下图是java.util.Arrays$ArrayList的简易源码,我们可以看到这个类重写的方法有哪些。

代码语言:javascript复制
private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
{
        ...

        @Override
        public E get(int index) {
          ...
        }

        @Override
        public E set(int index, E element) {
          ...
        }

        @Override
        public int indexOf(Object o) {
          ...
        }

        @Override
        public boolean contains(Object o) {
           ...
        }

        @Override
        public void forEach(Consumer<? super E> action) {
          ...
        }

        @Override
        public void replaceAll(UnaryOperator<E> operator) {
          ...
        }

        @Override
        public void sort(Comparator<? super E> c) {
          ...
        }
    }

我们再看一下java.util.AbstractListremove()方法,这样我们就明白为啥会抛出UnsupportedOperationException

代码语言:javascript复制
public E remove(int index) {
    throw new UnsupportedOperationException();
}

如何正确的将数组转换为ArrayList?

1. 自己动手实现(教育目的)

代码语言:javascript复制
//JDK1.5 
static <T> List<T> arrayToList(final T[] array) {
  final List<T> l = new ArrayList<T>(array.length);

  for (final T s : array) {
    l.add(s);
  }
  return l;
}

Integer [] myArray = { 1, 2, 3 };
System.out.println(arrayToList(myArray).getClass());//class java.util.ArrayList

2. 最简便的方法(推荐)

代码语言:javascript复制
List list = new ArrayList<>(Arrays.asList("a", "b", "c"))

3. 使用 Java8 的Stream(推荐)

代码语言:javascript复制
Integer [] myArray = { 1, 2, 3 };
List myList = Arrays.stream(myArray).collect(Collectors.toList());
//基本类型也可以实现转换(依赖boxed的装箱操作)
int [] myArray2 = { 1, 2, 3 };
List myList = Arrays.stream(myArray2).boxed().collect(Collectors.toList());

4. 使用 Guava(推荐)

对于不可变集合,你可以使用ImmutableList类及其of()copyOf()工厂方法:(参数不能为空)。

代码语言:javascript复制
List<String> il = ImmutableList.of("string", "elements");  // from varargs
List<String> il = ImmutableList.copyOf(aStringArray);      // from array

对于可变集合,你可以使用Lists类及其newArrayList()工厂方法:

代码语言:javascript复制
List<String> l1 = Lists.newArrayList(anotherListOrCollection);    // from collection
List<String> l2 = Lists.newArrayList(aStringArray);               // from array
List<String> l3 = Lists.newArrayList("or", "string", "elements"); // from varargs

5. 使用 Apache Commons Collections

代码语言:javascript复制
List<String> list = new ArrayList<String>();
CollectionUtils.addAll(list, str);

6. 使用 Java9 的 List.of()方法

代码语言:javascript复制
Integer[] array = {1, 2, 3};
List<Integer> list = List.of(array);
System.out.println(list); /* [1, 2, 3] */
/* 不支持基本数据类型 */

示例代码

一起来复习一下今天学习到的知识吧。

代码语言:javascript复制
public class Test {
    public static void main(String[] args){
 
       //1、对象类型(String型)的数组数组使用asList(),正常
        String[] strings = {"aa", "bb", "cc"};
        List<String> stringList = Arrays.asList(strings);
        System.out.print("1、String类型数组使用asList(),正常:  ");
        for(String str : stringList){
            System.out.print(str   " ");
        }
        System.out.println();
 
 
        //2、对象类型(Integer)的数组使用asList(),正常
        Integer[] integers = new Integer[] {1, 2, 3};
        List<Integer> integerList = Arrays.asList(integers);
        System.out.print("2、对象类型的数组使用asList(),正常:  ");
        for(int i : integerList){
            System.out.print(i   " ");
        }
//        for(Object o : integerList){
//            System.out.print(o   " ");
//        }
        System.out.println();
 
 
        //3、基本数据类型的数组使用asList(),出错
        int[] ints = new int[]{1, 2, 3};
        List intList = Arrays.asList(ints);
        System.out.print("3、基本数据类型的数组使用asList(),出错(输出的是一个引用,把ints当成一个元素了):");
        for(Object o : intList){
            System.out.print(o.toString());
        }
        System.out.println();
 
        System.out.print("   "   "这样遍历才能正确输出:");
        int[] ints1 = (int[]) intList.get(0);
        for(int i : ints1){
            System.out.print(i   " ");
        }
        System.out.println();
 
        //4、当更新数组或者List,另一个将自动获得更新
        System.out.print("4、当更新数组或者List,另一个将自动获得更新:  ");
        integerList.set(0, 5);
        for(Object o : integerList){
            System.out.print(o   " ");
        }
        for(Object o : integers){
            System.out.print (o   " ");
        }
        System.out.println();
 
        //5、add()   remove() 报错
        System.out.print("5、add()   remove() 报错:  ");
//        integerList.remove(0);
//        integerList.add(3, 4);
//        integerList.clear(); 
    }
 
}

0 人点赞