Arays.asList利用ガイド

5586 ワード

ネット上でArays.asListの使い方を説明する良い文章を見つけました.Java Aray to List Examples.文章の要点を下記のように整理し、個人的な見解を加えて、ご参考ください.
一、java.util.Arays.asList()の一般的な使い方
_; Listは、より豊かな動作のために配列をListに変換する必要があるならば、有用なデータ構造である.
String[] myArray = { "Apple", "Banana", "Orange" }; 
List myList = Arrays.asList(myArray);
  あるいは
List myList = Arrays.asList("Apple", "Orange");
上記の2つの形態は非常に一般的です.変換が必要な配列をパラメータとしたり、直接配列要素をパラメータとしたりして、変換が可能です.
二、極めて容易に発生するエラーと相応の解決策
エラー1:元のデータタイプのデータの配列をパラメータとします.
前に述べたように、変換が必要な配列をasList方法のパラメータとすることができる.今は整体行列を変える必要があるとすれば、当然のようにしたい人もいるかもしれません.
public class Test {
   public static void main(String[] args) {
      int[] myArray = { 1, 2, 3 };
      List myList = Arrays.asList(myArray);
      System.out.println(myList.size());
   }
}
上記のコードの出力結果はなんですか?上のコードを自然に書いてくれる人がいれば、myListの大きさは3だと思っています.残念ですが、このコードの出力結果は3ではなく、1です.myListを遍歴してみると、1、2、3のいずれかではなく、hashCodeを持つ対象が見つかってきます.どうしてですか?  asList方法の署名を見てみます.
public static  List asList(T... a)
パラメータの種類はTであり、公式文書によると、Tは配列要素のクラスである.反射技術に詳しいなら、クラスの意味はきっと自明です.どのタイプのオブジェクトにもクラス属性があることを知っています.この属性はこのタイプ自身を表しています.オリジナルデータタイプは、例えばint、ショート、longなど、この属性がないもので、クラスの属性を持つものは、それらに対応するパッケージ類Integer、Shott、Longです.したがって、このエラーが発生した原因は、asList方法のパラメータは対象または対象配列でなければならず、元のデータタイプは対象ではないと解釈できる.元のデータ型配列が導入されたとき、asListの本当に得られたパラメータは配列の要素ではなく、配列のオブジェクトそのものです.このときListの唯一の要素はこの配列である.
ソリューション:パッケージ配列を使用する
_; の配列をListに変換する必要があるなら、配列のタイプをintではなくIntegerとして宣言します.
public class Test {
   public static void main(String[] args) {
      Integer[] myArray = { 1, 2, 3 };
      List myList = Arrays.asList(myArray);
      System.out.println(myList.size());
   }
}
この時のmyListの大きさは3です.遍歴すれば1、2、3を得ます.この案は比較的簡潔明瞭である.  実は文章の中で、著者はもう一つの解決策を使っています.彼はJava 8が新しく導入したAPIを使っています.
public class Test {
   public static void main(String[] args) {
      int[] intArray = { 5, 10, 21 };
      //Java 8      Stream   
      List myList = Arrays.stream(intArray).boxed().collect(Collectors.toList());
   }
}
_; はJava 8のこの新しい特性についてあまり知らないので、ここでは詳しく述べないで、興味がある友達は自分で関連資料を調べられます.
エラー2:Listのサイズを変更しようとします.
Listはダイナミックに拡大できることを知っていますので、Listを作成した後によく見られる操作は、その中に新しい要素を追加するか、または中から既存の元素を削除することです.
public class Test {
   public static void main(String[] args) {
      String[] myArray = { "Apple", "Banana", "Orange" };
      List myList = Arrays.asList(myArray);
      myList.add("Guava");
   }
}
このコードを実行しようと試みたところ、java.lang.UnsupportedOperationExceptionの異常が出ました.この異常はmyListに新しい元素を追加することが許されないことを意味します.myListから元素を削除しようとすると、同じ異常が出てきます.どうしてですか?  公式文書をよく読むと、asList方法についての説明にこんな言葉があります.
指定された配列で生成された固定サイズのListを返します.
  答えが発表され、asList方式で生成されたListは固定サイズであり、その大きさを変更する操作は一切許されないことを意味する.そんなに新しい問題が来ました.道理でListは動的拡充を支持しています.どうしてasList方法によって生まれたListは固定サイズですか?この問題に答えるには、ソースの確認が必要です.Java 8のasListメソッドのソースコードは以下の通りです.
@SafeVarargs
@SuppressWarnings("varargs")
public static  List asList(T... a) {
    return new ArrayList<>(a);
}
_; 方法の中にArayListが確かに生成されました.これは動的拡大を支持するべきではないですか?焦らないで、続けて見てください.asListメソッドのすぐ後ろに、このような内部クラスがあります.
private static class ArrayList extends AbstractList 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;
    }

    //...
}
この内部クラスもArayListと呼ばれ、さらに重要なのは、この内部クラスにfinalとして宣言された配列aがあり、すべての着信要素がこの配列aに保存されます.ここで、答えはまた発表されました.asList方法は確かにArayListですが、このArayListはjava.util.ArayListではなく、java.util.Araysの部類です.この内部クラスは一つのfinal配列で要素を保存するので、asList法で生成されたArayListはサイズを変更することができない.
解決策:本物のArayListを作成します.
私たちはすでにasList方法によって生成されたArayListのサイズを変更できないことを知っています.このArayListは「本物の値段」のArayListではないので、自分で本当のArayListを作成します.
public class Test {
   public static void main(String[] args) {
      String[] myArray = { "Apple", "Banana", "Orange" };
      List myList = new ArrayList(Arrays.asList(myArray));
      myList.add("Guava");
   }
}
上記のコードの中に、newはjava.util.ArayListを作りました.そしてasList方法の戻り値をコンストラクタのパラメータとして伝えました.最後に得たmyListは自然にダイナミックに拡大できます.
三、自分の方法でListへの配列転換を実現する.
  時には、自分で一つの方法を実現するのがライブラリの中の方法よりいいです.asList方法にはいくつかの制限がありますので、Listへの配列転換は自分の方法で実現できます.
public class Test {
   public static void main(String[] args) {
      String[] myArray = { "Apple", "Banana", "Orange" };
      List myList = new ArrayList();
      for (String str : myArray) {
         myList.add(str);
      }
      System.out.println(myList.size());
   }
}
  こうすれば自然に目的を達成することができますが、明らかに欠点があります.コードが長いです.しかも、これは自分で車輪を作るのと同じです.もちろん、自分で方法の利益を実現するのも明らかで、どんな需要があっても、自分で満足すればいいです.例えば、配列の各要素をListに2回追加する必要がある:
public class Test {
   public static void main(String[] args) {
      String[] myArray = { "Apple", "Banana", "Orange" };
      List myList = new ArrayList();
      for (String str : myArray) {
         myList.add(str);
         myList.add(str);
      }
      System.out.println(myList.size());
   }
}
つまり、問題の解決案は一つだけではなく、効率のために既存の車輪を使って問題を解決することがよくありますが、もし制限がないなら、他の案を試してみてもいいです.