Help us understand the problem. What is going on with this article?

java.util.Arrays.asList()はnew ArrayList<>()の代替ではない

More than 1 year has passed since last update.

今回は「java.util.Arrays.asList()new ArrayList<>()の代替ではない」という話について説明したいと思います。
いきなりですが例題です。

before
List<String> fruts = new ArrayList<>();
fruts.add("apple");
fruts.add("orange");
fruts.add("strawberry");

after
List<String> fruts = Arrays.asList("apple", "orange", "strawberry");

短くなるからと改修させるレビュアーは危険です。

このインターフェースなら全部動くと思いますか?
void show(List<String> fruts);

コレクションとして操作しているなら問題ありませんが、インターフェースの実装によってはエラーとなる場合があるからです。

インスタンスの型を見れば分かりますがjava.util.Arrays.asList()で作成されるインスタンスはjava.util.ArrayListではなくjava.util.Arrays$ArrayListです。
問題が発生するとしたらこの違いに関するところになります。
以下のデモアプリで確認してみましょう。

デモアプリ
package com.example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Demo {

    public static void main(String[] args) {
        List<String> fruts1 = new ArrayList<>();
        fruts1.add("apple");
        fruts1.add("orange");
        fruts1.add("strawberry");
        show(fruts1);
        System.out.println("------------------------------------------------------------");
        List<String> fruts2 = Arrays.asList("apple", "orange", "strawberry");
        show(fruts2);
    }

    private static void show(List<String> fruts) {
        System.out.println(fruts + " is " + fruts.getClass().toString());
        if (java.util.ArrayList.class.isAssignableFrom(fruts.getClass())) {
            System.out.println("OK : java.util.ArrayList.class.isAssignableFrom(fruts.getClass())");
        } else {
            System.out.println("NG : java.util.ArrayList.class.isAssignableFrom(fruts.getClass())");
        }
        if (java.util.List.class.isAssignableFrom(fruts.getClass())) {
            System.out.println("OK : java.util.List.class.isAssignableFrom(fruts.getClass())");
        } else {
            System.out.println("NG : java.util.List.class.isAssignableFrom(fruts.getClass())");
        }
        if (java.util.ArrayList.class.isInstance(fruts)) {
            System.out.println("OK : java.util.ArrayList.class.isInstance(fruts)");
        } else {
            System.out.println("NG : java.util.ArrayList.class.isInstance(fruts)");
        }
        if (java.util.List.class.isInstance(fruts)) {
            System.out.println("OK : java.util.List.class.isInstance(fruts)");
        } else {
            System.out.println("NG : java.util.List.class.isInstance(fruts)");
        }
        if (fruts instanceof java.util.List) {
            System.out.println("OK : fruts instanceof java.util.List");
        } else {
            System.out.println("NG : fruts instanceof java.util.List");
        }
        if (fruts instanceof java.util.ArrayList) {
            System.out.println("OK : fruts instanceof java.util.ArrayList");
        } else {
            System.out.println("NG : fruts instanceof java.util.ArrayList");
        }
        try {
            List<String> castObj = (List<String>) fruts;
            System.out.println("OK : List<String> castObj = (List<String>) fruts;");
        } catch(Exception e) {
            e.printStackTrace();
        }
        try {
            List<String> castObj = (ArrayList<String>) fruts;
            System.out.println("OK : List<String> castObj = (ArrayList<String>) fruts");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
動作結果
[apple, orange, strawberry] is class java.util.ArrayList
OK : java.util.ArrayList.class.isAssignableFrom(fruts.getClass())
OK : java.util.List.class.isAssignableFrom(fruts.getClass())
OK : java.util.ArrayList.class.isInstance(fruts)
OK : java.util.List.class.isInstance(fruts)
OK : fruts instanceof java.util.List
OK : fruts instanceof java.util.ArrayList
OK : List<String> castObj = (List<String>) fruts;
OK : List<String> castObj = (ArrayList<String>) fruts
------------------------------------------------------------
[apple, orange, strawberry] is class java.util.Arrays$ArrayList
NG : java.util.ArrayList.class.isAssignableFrom(fruts.getClass())
OK : java.util.List.class.isAssignableFrom(fruts.getClass())
NG : java.util.ArrayList.class.isInstance(fruts)
OK : java.util.List.class.isInstance(fruts)
OK : fruts instanceof java.util.List
NG : fruts instanceof java.util.ArrayList
OK : List<String> castObj = (List<String>) fruts;
java.lang.ClassCastException: java.util.Arrays$ArrayList cannot be cast to java.util.ArrayList
    at com.example.Demo.show(Demo.java:59)
    at com.example.Demo.main(Demo.java:17)

一応インターフェースで隠ぺいされているので、Arrays.asListに置き換えても「必ず動く」という認識は改めた方がいいでしょう。

といっても根本的にはその実装に問題があるのですが、、、
著者は「java.lang.ClassCastException: java.util.Arrays$ArrayList cannot be cast to java.util.ArrayList」に遭遇してしまったので、今回の記事を書くことにしました。
インターフェース上は問題ないので、実行時までエラーになるとは判明しませんでした。

今回のタイトルも正しくは「java.util.Arrays.asList()new ArrayList<>()を置き換えると実装によってはエラーになる」です。

(2018/11/24 追記)

どうしてもListを1行で定義、初期化したい場合の答え

(方法1)Arrays.asList()をArrayListのコンストラクタに設定
List<String> fruts = new ArrayList<>(Arrays.asList("apple", "orange", "strawberry"));

Arrays.asList()を使えと指摘するなら、コンストラクタと合わせて使うのが適切です。

(方法2)インスタンス生成時にメソッドを呼ぶ
List<String> fruts = new ArrayList<String>() {
    {
        add("apple");
        add("orange");
        add("strawberry");
    }
};

(方法2)は少し記述方法が独特ですが、文法上これも正しいです。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away