java source analysis Arrays.asList method

  • 2020-05-12 02:33:50
  • OfStack

Recently, I took time to do the source code analysis of java Arrays tool class asList method, organized the relevant information on the Internet, down, hope to help readers!

The Arrays utility class provides a method, asList, that converts a variable-length parameter or array to List.

The source code is as follows:


 /**
  * Returns a fixed-size list backed by the specified array. (Changes to
  * the returned list "write through" to the array.) This method acts
  * as bridge between array-based and collection-based APIs, in
  * combination with {@link Collection#toArray}. The returned list is
  * serializable and implements {@link RandomAccess}.
  *
  * <p>This method also provides a convenient way to create a fixed-size
  * list initialized to contain several elements:
  * <pre>
  *  List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
  * </pre>
  *
  * @param a the array by which the list will be backed
  * @return a list view of the specified array
  */
 @SafeVarargs
 public static <T> List<T> asList(T... a) {
  return new ArrayList<>(a);
 }
 

The problem found

Based on the description of the above method, let's write some examples first:


/**
 * @author wangmengjun
 *
 */
public class ArrayExample {
 
 public static void main(String[] args) {
  
  /** Use variable length parameters */
  List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
  System.out.println(array1);
  
  /** Use an array */
  List<String> array2 = Arrays.asList(new String[] {"Welcome", "to","Java", "world"});
  System.out.println(array2);
 }

}

Run the above program and output the following.

[Welcome, to, Java, world]
[Welcome, to, Java, world]

On a whim, I suddenly want to add a string "Cool~~~" to the list created.


 /** Use variable length parameters */
  List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
  array1.add("Cool~~~");

As a result, an UnsupportedOperationException anomaly was encountered:


Exception in thread "main" java.lang.UnsupportedOperationException
 at java.util.AbstractList.add(Unknown Source)
 at java.util.AbstractList.add(Unknown Source)
 at test.ArrayExample.main(ArrayExample.java:36)

Amazing, new ArrayList < > The list generated by (a) calls the add method and encounters a problem.

The reason to find

So the question is, what happened? With that in mind, check out 1 to see what ArrayList actually looks like in Arrays.asList.

The ArrayList class used by Arrays's asList method was an internally defined class, not the java.util.ArrayList class.

The source code is as follows:


 /**
   * @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) {
      if (array==null)
        throw new NullPointerException();
      a = array;
    }

    public int size() {
      return a.length;
    }

    public Object[] toArray() {
      return a.clone();
    }

    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;
    }

    public E get(int index) {
      return a[index];
    }

    public E set(int index, E element) {
      E oldValue = a[index];
      a[index] = element;
      return oldValue;
    }

    public int indexOf(Object o) {
      if (o==null) {
        for (int i=0; i<a.length; i++)
          if (a[i]==null)
            return i;
      } else {
        for (int i=0; i<a.length; i++)
          if (o.equals(a[i]))
            return i;
      }
      return -1;
    }

    public boolean contains(Object o) {
      return indexOf(o) != -1;
    }
  }

As you can see from the implementation of this inner class ArrayList, it inherits the abstract class java.util.AbstractList < E > , but it does not override the add and remove methods, nor does it give a concrete implementation.

However, by default, the java.util.AbstractList class throws UnsupportedOperationException exceptions directly in the add, set, and remove methods. Part of the source code of AbstractList is as follows:


public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
  /**
   * Sole constructor. (For invocation by subclass constructors, typically
   * implicit.)
   */
  protected AbstractList() {
  }

  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();
  }
}

Because the java.util.Arrays inner class ArrayList does not override the add and remove methods, when we call its add method, we are actually calling the add method of AbstractList class, and the result is an UnsupportedOperationException exception.

Similarly, an UnsupportedOperationException exception is encountered when calling the remove method, or when calling other methods (such as addAll) that are associated with the add or remove methods.

Examples of addAll:


/**
 * @author wangmengjun
 *
 */
public class ArrayExample {

  public static void main(String[] args) {

    /** Use variable length parameters */
    List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
    array1.addAll(Arrays.asList("AAA", "BBB"));
  }

}


Exception in thread "main" java.lang.UnsupportedOperationException
 at java.util.AbstractList.add(Unknown Source)
 at java.util.AbstractList.add(Unknown Source)
 at java.util.AbstractCollection.addAll(Unknown Source)
 at test.ArrayExample.main(ArrayExample.java:36)
 

Examples of set:


/**
 * @author wangmengjun
 *
 */
public class ArrayExample {

  public static void main(String[] args) {

    /** Use variable length parameters */
    List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
    System.out.println(array1);
    
    // will Java replace hello
    array1.set(2, "hello");
    System.out.println(array1);
  }

}

Because ArrayList, the inner class of Arrays, overrides the set method, the above program works without throwing an UnsupportedOperationException exception.

The results are as follows:

[Welcome, to, Java, world]
[Welcome, to, hello, world]

Usage scenarios

From the above example and simple analysis, the Arrays tool class provides a method, asList, that converts a variable length parameter or array to List.

However, the length of the generated List is fixed; Ability to modify operations (for example, modify elements in a location); Cannot perform operations that affect length (such as add, remove, etc.). An UnsupportedOperationException exception is thrown.

Arrays.asList is ideal for situations where you already have array data or one element, and you need to quickly build an List for read operations only, not add or remove operations.

If, according to the known array data, you want to quickly obtain a list List that can be added, deleted, modified and checked, a simpler method is as follows:

Reuse java.util.ArrayList packaging layer 1.


/**
 * @author wangmengjun
 *
 */
public class ArrayExample {

  public static void main(String[] args) {

    /** Use variable length parameters */
    List<String> array1 = new ArrayList<>(Arrays.asList("Welcome", "to", "Java", "world"));
    System.out.println(array1);

    array1.add("Cool~~~");
    System.out.println(array1);

  }

}

The results are as follows:

[Welcome, to, Java, world]
[Welcome, to, Java, world, Cool~~~]

Thank you for reading, I hope to help you, thank you for your support of this site!


Related articles: