java.utilまとめ4（Arrays、List、ListIterator）


今回かくこと：

- Arraysクラス
- Listインターフェース
- ListIteratorインターフェース

## Arraysクラス
このクラスは配列をいろいろと操作をすることが可能なクラス。
このクラスの特徴としてはすべてのメソッドがstatic（静的）なので、Arraysクラスのメソッドを使うときは必ず、Arrays.をつけてから（例えば、後述する`Arrays.asList(...)`、`Arrays.addAll(...)`みたいに）でないと使わなければならない。

### asListメソッド
このクラス（Arraysクラス）で定義されていて、配列を**固定長リスト**に変換するメソッド。

例えば、簡単なコードで

```java:AsListSample1.java
import java.util.Arrays;
import java.util.List;

public class AsListSample1 {
	
	public static void main(String[] args){
		String[] strs = {"a","b","c"};
		
		List<String> list = Arrays.asList(strs);
		System.out.println(list);
	}
}
```

を実行すると、

```
[a, b, c]
```

と結果が出てくる。
しかし、次のコードだと例外が返ってくるので注意。

```java:AsListSample2.java
import java.util.Arrays;
import java.util.List;

public class AsListSample2 {
	
	public static void main(String[] args){
		String[] strs = {"a","b","c"};
		
		List<String> list = Arrays.asList(strs);
		list.add("d");
		
		System.out.println(list);
	}
}
```

```
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractList.add(AbstractList.java:148)
	at java.util.AbstractList.add(AbstractList.java:108)
	at com.test.java.util.AsListSample2.main(AsListSample2.java:12)
```

これは先ほども書いたようにasListメソッドが**固定長リストとして**返すので、List型に変換したからといって、可変長になるわけではなく、リストの長さが変わるようなことをすると例外を投げてくる。なので、List型に変換した後に、addやremoveなんてことはできない仕様になっている。

ただ、これだけだと使っても代償が残る形であまり使う気にならなくなるが、解決策としては次のようなコードであらかじめ**可変長として**リストに返せばよい。

```java:AsListSample3.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class AsListSample3 {
	
	public static void main(String[] args){
		String[] strs = {"a","b","c"};
		
		List<String> list = new ArrayList<String>(Arrays.asList(strs));
		list.add("d");
		
		System.out.println(list);
	}
}
```

すると

```
[a, b, c, d]
```

ちゃんと例外を投げずに返ってくる。
ついでに、数値のようなプリミティブ型は例外は投げないものの、リストなどでは使えないので（[方法はあるが](http://qiita.com/landrunner/items/d4894b3bab649f64a674)）、注意が必要。

### copyOfメソッド
このクラスで定義されており、指定した配列を他の配列へ指定した長さまでコピーするメソッド。その際、コピー先の配列の長さを変えることもできる。

第1引数には、配列型のboolean、byte、char、double、float、int、long、short、オブジェクトをコピーさせたい配列として指定でき、第2引数にはコピー先の配列の長さを指定できる。オブジェクトの配列型に限り、第3引数が存在し、コピー先のクラス型（スーパークラス）を継承したクラス（サブクラス）を指定して新しいクラス配列型として指定できる。

簡単な例だが、

```java:CopyOfSample.java
import java.util.Arrays;

public class CopyOfSample {
	
	public static void main(String[] args){
		String[] strs = {"a","b","c"};
		String[] copyStrshort = Arrays.copyOf(strs,2);
		String[] copyStrs = Arrays.copyOf(strs,6);
		
		for(int i = 0; i < copyStrs.length; i++){
			
			if(copyStrshort.length > i){
				System.out.println("配列copyStrshortの" + i + "番目は → " + strs[i]);
			}
			
			System.out.println("配列copyStrs    の" + i + "番目は → " + copyStrs[i]);
		}
	}
}
```

実行結果は

```
配列copyStrshortの0番目は → a
配列copyStrs    の0番目は → a
配列copyStrshortの1番目は → b
配列copyStrs    の1番目は → b
配列copyStrs    の2番目は → c
配列copyStrs    の3番目は → null
配列copyStrs    の4番目は → null
配列copyStrs    の5番目は → null
```

となる。

ここで、
copyOfメソッドでコピーされた配列は、コピー先の配列がコピー元の配列と長さが余ったり、元の配列よりも短くても自動的に処理をしてくれる。短かった場合は指定した長さまでの要素をコピー先の配列に入れられる。コピー先の配列が元の配列より長かった場合は余った要素部分にそれぞれその型の初期値が自動的に入れられる。

一応、自動的に入る初期値は以下のようになる：

| 型 | 余った要素に入る値 |
|:------------|:-------------:|
| boolean | false |
| byte | 0 |
| char | '\\u000' |
| double | 0.0 (0d) |
| float | 0.0 (0f) |
| int | 0 |
| long | 0 (0L) |
| short | 0 |
| オブジェクト | null |

## Listインターフェース
`List<> list = new ArrayList<>()`でおなじみのList。こういう風に書くのはこの後に何かしらの拡張性を持たせようという意図があってやっている（例えば、List型にしかないメソッドを使いたいときとか）とか、可読性が増すとか。ただ、この後に拡張性を持たせないという意味で使うならList型にするのはよろしくない。このインターフェースを実装しているクラス（ArrayList、LinkedListとか）は大体このListインターフェース内で定義されている。

### addメソッド、addAllメソッド
Collectionインターフェースで定義されているメソッド。リストに要素を追加するメソッド。addAllメソッドの方は指定したコレクションを丸ごとリストに追加するメソッド。第1引数にリストのインデックスを超えない範囲で始めに要素を入れる位置を指定することもできる。

配列の要素をすべてリストに入れてから新たに要素を追加する例、

```java:ListSample.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ListSample {

	public static void main(String[] args) {
		String[] strs = {"a","b","c"};
		List<String> list = new ArrayList<String>();
		
		list.addAll(Arrays.asList(strs));
		
		System.out.println("First add " + list);
		
		list.add("d");
		list.add(2,"h");
		
		System.out.println("Second add " + list);
	}
}
```

結果は

```
First add [a, b, c]
Second add [a, b, h, c, d]
```

### toArrayメソッド
Collectionインターフェースで定義されているメソッド。
リストを配列に変換するメソッド。asListメソッド逆のメソッドみたいなもの。
引数に返したい配列型を指定できる。

前の例のコードの続きとして、

```java:ListSample.java（続き）
System.out.println("Objectととして変換: ");
		
for(Object item : list.toArray()){
	System.out.println(item);
}
		
System.out.println();
System.out.println("Stringととして変換: ");
	
for(String item : list.toArray(new String[list.size()])){
	System.out.println(item);
}
```

結果は

```
Objectととして変換: 
a
b
h
c
d

Stringととして変換: 
a
b
h
c
d
```

最初の例は単純で簡単な例で、2番目の例はStringの要素として持っているリストをObjectとして出すのが気持ち悪かったので、文字数は多少多めだけど、String型として渡している例。

### listIteratorメソッド
List型を（後述する）ListIterator型として返してくれるメソッド。引数を指定（インデックス番号）するとListIterator型のnextメソッドでその指定した引数がインデックスとして最初に呼び出されるものとなる。

## ListIteratorインターフェース
リストのためのイテレータを用意するインターフェース。現在の要素を持たない。そこを生かして、前方向だけでなく逆方向からの検索が可能になっている。

### hasNext、nextIndex、nextメソッド
nextIndexメソッド以外はIteratorインターフェースで定義されていて、nextIndexメソッドはこのインターフェースで定義されている。

hasNextメソッドは次のインデックスに要素があるときにtrueを返すメソッド。
nextIndexメソッドはnextメソッドを呼び出したときに返される要素のインデックスを返すメソッド。
nextメソッドは次の要素を返し、さらに前にカーソルが移動するメソッド。

簡単な例として、

```java:ListIteratorSample.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

public class ListIteratorSample {

	public static void main(String[] args) {
		String[] strs = {"a","b","c","d"};
		List<String> list = new ArrayList<String>(Arrays.asList(strs));
		ListIterator<String> listIterator = list.listIterator();
		
		while(listIterator.hasNext()){
			System.out.println("インデックス " + listIterator.nextIndex() + " の要素は " + listIterator.next());
		}
	}
}
```

結果は

```
インデックス 0 の要素は a
インデックス 1 の要素は b
インデックス 2 の要素は c
インデックス 3 の要素は d
```

## おわり
ListIteratorインターフェースで逆方向検索ができると書いたがそれはまたの機会で...