ジェネリックメソッド
型ごとに、同じメソッドを書き写している
配列の 2 つの要素を入れ替える処理を、型ごとに用意するとこうなります。
Java
public static void swap(String[] items, int i, int j) {
String tmp = items[i];
items[i] = items[j];
items[j] = tmp;
}
public static void swap(Integer[] items, int i, int j) {
Integer tmp = items[i];
items[i] = items[j];
items[j] = tmp;
}中身はまったく同じで、違うのは型の名前だけです。Double や LocalDate が必要になれば、そのたびに同じ 5 行が増えていきます。かといって Object[] で受けると、呼び出し側で型が失われてしまいます。
クラス全体を <T> 付きにする手もありますが、入れ替えたいだけのために専用のクラスを作るのは大げさです。こういうときは、メソッド 1 つに型パラメータを付けます。
<T> は戻り値の型の直前に書く
Java
public static <T> void swap(T[] items, int i, int j) {
T tmp = items[i];
items[i] = items[j];
items[j] = tmp;
}static と void の間に挟まっている <T> が、このメソッドの中だけで通じる型 T をここで宣言します、という印です。位置は文法で決まっていて、修飾子のあと、戻り値の型の直前です。public <T> static void のように順番を入れ替えたり、戻り値の型より後ろに書いたりするとコンパイルエラーになります。
宣言した T は、引数の型でも、戻り値の型でも、メソッドの中の変数でも使えます。有効なのはこのメソッドの中だけで、隣のメソッドの T とは何の関係もありません。
呼ぶときは <String> を書かない
型パラメータは、呼び出し側で明示することもできます。
Java
String[] names = {"sato", "abe"};
Util.<String>swap(names, 0, 1); // 書けるが、普段は書かない
Util.swap(names, 0, 1); // 引数から T は String だと分かるコンパイラは渡された引数の型を見て T が何かを判断します。これを型推論と呼び、new ArrayList<>() の空の山かっこが通るのも同じ仕組みです。明示するのは、引数からは決めようがない場面だけです。
課題のメソッドは int[] を受け取る形で最初から決まっています。プリミティブ型の配列は T[] では受けられないため、ここは型パラメータの出番ではありません。シグネチャはそのままにして、中身だけを書いてください。要素が 1 つも無いときにどうするかを先に決めてから、残りを書くと迷いません。
要件
- メソッドは
public static int firstOf(int[] arr)のシグネチャを維持すること arr.length == 0のとき0を返すこと- 空でないときは
arr[0]をそのままreturnすること (arr[1]などにしない)
入出力例
firstOf([5,10,15]) → 5
firstOf([]) → 0
firstOf([42]) → 42
firstOf([-3,-1,-2]) → -3