第2回目の講義で配列を作成するときは,List
を使うように述べました.
ここでは,List
の使い方を学びます.
Java言語に限らずList
とはデータ構造の一つで,順序を持つ複数のデータを扱います.
要するに配列を置き換えるものです.List
の特徴は次の通りです.
基本的な特徴は配列と同じです.
しかし,配列にはない特徴もあります.例えば,サイズを生成時に決める必要がない,
やサイズが自動的に増減するなどです.List
は配列よりも優れた特徴を持つ型ですから,
配列ではなく,List
を積極的に使っていきましょう.
Java言語では順序を持つデータの集合をList
と呼びます.
その実現方法は配列を用いる方法,リンクリストを用いる方法の2種類があります.
それぞれの実現方法には向いている点,向いていない点が存在します.
そのため,Javaにはそれぞれの実現方法でList
を実現する型が
存在します.ArrayList
とLinkedList
の2つの型です.どちらを使っても処理の違いはありませんが,
処理内容によっては実行速度が違ってくる可能性があります.
とはいえ,その違いが効いてくるのは,もっと大規模で,実行速度が重視される場合ですから,今は気にしなくても良いでしょう.
リンクリストの詳細については,FAQ のリンクリストとは何ですかを参照してください.
基本的にArrayList
もLinkedList
も使い方に違いはありません.
以下の例では,ArrayList
で説明していますが,ArrayList
をLinkedList
に置き換えても
同じ説明が成り立ちますので,適宜読み替えてください.
なお,ArrayList
を使うときには,import
文が必要です.import java.util.ArrayList;
とクラス宣言の前に書きましょう.
Java言語でList
を使うには,今までとは少し異なる宣言方法が必要です.
データ構造にどのような型の変数を格納するかを型宣言に含める必要があります.
例えば,ArrayList
にString
型や,Integer
型を格納しようとすると,次のような宣言が必要になります.
// String型を格納する ArrayList.
ArrayList<String> listForStrings =
new ArrayList<String>();
// Integer型を格納する ArrayList.
ArrayList<Integer> listForIntegers =
new ArrayList<Integer>();
上記のように,ArrayList<格納する型>
という型として宣言しなければならず,また,
実体を作成するときも,new ArrayList<格納する型>()
のように作成しなければいけません.
格納する型が異なるとコンパイルエラーが発生します.
なお,実体を作成するときの格納する型は,下のように省略できます.以下のコードは上に挙げたコードと全く同じ結果になります.
ArrayList<String> listForStrings = new ArrayList<>();
ArrayList<Integer> listForIntegers = new ArrayList<>();
一般的に List
に対して行える操作は4種類です.
その操作は,CRUDと呼ばれます.作成(Create),読み取り(Read),更新(Update),削除(Delete)の4種類です.
以降の説明は,次に示すArrayList
型の変数に対してメソッドを呼び出すものとして読み進めてください.
ArrayList<String> list = new ArrayList<>();
// ArrayList<String> list = new ArrayList<String>();
String value1 = // ...
list.add(value1);
list.add("Haruaki Tamada");
// list.add(9); // => コンパイルエラーが発生する.
// 9 は String型ではないため.
list.add("9"); // => OK."9"は文字列.
データを追加するには,上のサンプルのようにadd
メソッドを用います.
データ集合の最後に追加されていきます.用意されている長さを超えて追加しようとすると,自動的に長さが伸びていくため,
理論上は,無制限にデータを追加できます.
String item1 = list.get(0);
// => listのインデックスも配列と同じように0から始まる.
String item2 = list.get(1);
String item100 = list.get(100);
// => 範囲を超えてアクセスしようとすると,実行時に
// IndexOutOfBoundsException というエラーが発生する.
上のサンプルのように,get
メソッドを呼び出すことで,List
内の特定の要素を取得できます.
返り値の型は,ArrayList
型の変数の宣言時に指定した型でなければいけません.
list.set(1, "TAMADA, Haruaki");
特定の要素を置き換える場合は,set
メソッドが利用できます.
インデックスと置き換え後のデータを指定すると,データの更新が可能です.
指定したインデックスに要素が存在しない場合は,IndexOutOfBoundsException
というエラーが発生します.
list.remove(1);
指定したインデックスの要素を削除したい場合は,remove
メソッドを
利用します.remove
を使って削除したあと,後ろの要素は詰められます.
すなわち,次のコードで全ての要素を順番に削除できます.
while(!list.isEmpty()){ // listが空じゃない間繰り返す.
list.remove(0); // 一番最初の要素を削除する.
}
List
の現在のサイズ(長さ)を取得する場合は,size
メソッドを利用しましょう.
文字列の長さ,配列の長さと混同しやすいため,注意してください.
String
型)の長さ
string.length()
(メソッド呼び出しで取得するため括弧が必要).array.length
(変数アクセスのため,括弧は不要).Java言語での List
の繰り返しは,次の3種類が利用できます.
一番典型的な方法です.ただし,ループの途中で list
の要素数を変化させることは
混乱の元になるので,ループ内での List
への値の追加・削除は行わない方が良いでしょう.
for(Integer i = 0; i < list.size(); i++){
String item = list.get(i);
// ここに繰り返しの処理を書く.
}
Iterator
型を利用する方法.Javaらしい書き方.
for(Iterator<String> iterator = list.iterator();
iterator.hasNext(); ){
String item = iterator.next();
// ここに繰り返しの処理を書く.
}
拡張for文と呼ばれる書き方.実質的には,Iteartor
型を利用する方法と同じ.
コンパイラがIterator
型を利用する方法に変換してコンパイルする.最近はこの書き方が多い.
for(String item: list){
// ここに繰り返しの処理を書く.
}
コマンドライン引数に受け取ったString
型の値を全て ArrayList
に入れ,ArrayList
から順に取り出し,出力するプログラムを書きましょう.
import java.util.ArrayList;
public class ArgsPrinter2{
void run(String[] args){
ArrayList<String> list = this.buildList(args);
this.printList(list);
}
ArrayList<String> buildList(String[] array){
ArrayList<String> arrayList = new ArrayList<>();
for(Integer i = 0; i < array.length; i++){
arrayList.add(array[i]);
}
return arrayList;
}
void printList(ArrayList<String> arrayList){
for(String item: arrayList){
System.out.println(item);
}
}
public static void main(String[] args){
ArgsPrinter2 printer = new ArgsPrinter2();
printer.run(args);
}
}
このプログラムを書き,コンパイル,実行してみましょう.実行時にコマンドライン引数に値を指定して実行してみましょう.
50個のDouble
型の 0〜1の乱数をArrayList
に入れて,出力してみましょう.
クラス名は,DoubleValuePrinter
としてください.
乱数の発生方法は,Big & Smallを参照してください.
なお,リストを生成する部分,出力する部分を別のメソッドにしてみましょう.
クラス名はDoulbeValuePrinter
としましょう.
完成すれば,コマンドライン引数で発生させる乱数の個数を指定できるようにしてください. 指定されなければ,50個としてください.
$ java DoubleValuePrinter
1: 0.24279591112755294
2: 0.7216985840426494
3: 0.5978665614812361
... 途中省略
48: 0.15288776496056167
49: 0.8335019950136539
50: 0.8114170360899468
$ java DoubleValuePrinter 3
1: 0.20585052641970603
2: 0.578743233682112
3: 0.107553196759134