map で変換する
入れ物を先に用意するのが面倒
名前のリストから、それぞれの文字数のリストを作りたいとします。for で書くと、まず空のリストを用意するところから始まります。
Java
List<Integer> lengths = new ArrayList<>();
for (String name : names) {
lengths.add(name.length());
}やりたいのは「文字数に変える」だけなのに、入れ物を作る行と、そこに詰める行が必要です。しかも lengths は宣言してから中身が入るまで空っぽの状態が続くので、途中で return を書き足すと未完成のリストが漏れます。
map を使うと、変換の中身だけを書けば済みます。
Java
List<Integer> lengths = names.stream()
.map(name -> name.length())
.toList();map は個数を変えず、型だけ変える
map に渡すのは「1 つ受け取って、1 つ返す」式です。要素ごとに 1 対 1 で入れ替えるので、3 件流せば必ず 3 件出てきます。件数を減らしたいときは filter の出番で、map は形の担当です。
そのかわり、map は Stream の型を変えます。names は Stream<String> ですが、name.length() が返すのは数値なので、map を通した後は Stream<Integer> になります。元の型と違う型を返してよい、というのが map のいちばんの働きどころです。
map は filter と同じ中間操作なので、書いただけでは何も起きません。toList() のような終端操作を呼んだときに、はじめて全要素が変換されます。
数値の Stream には数値を返す
IntStream にも map があります。摂氏の配列を華氏に直すなら、こう書けます。
Java
int[] fahrenheit = IntStream.of(celsius)
.map(c -> c * 9 / 5 + 32)
.toArray();ここで 1 つ、はまりやすい制限があります。IntStream の map は int を受け取って int を返す式しか受け付けません。
Java
IntStream.of(celsius).map(c -> c + " 度"); // コンパイルエラー数値の Stream から文字列や自作クラスに変えたいときは、map ではなく mapToObj を使います。逆に Stream<String> から数値の Stream に落としたいときは mapToInt です。名前が違うだけで、やっていることはどれも「1 つ受け取って 1 つ返す」で同じです。
数値を数値のまま扱う
IntStreamには、合計や平均を出す終端操作がそろっています。Stream<Integer>にはこれらが無いので、数を集計するときはIntStreamに寄せるのが定番です。
やってみよう
Solution.squareSum(int[] arr) を完成させて、各要素を 2 乗した合計を返してください。
Arrays.stream(arr) で IntStream を作り、map に 2 乗する式を渡してから、合計を出す終端操作 sum() を呼びます。for を回して自分で足し込むのは禁止です。map で形を変えてから集計する、という流れをここで通しておいてください。
戻り値は int で、sum() が返すのも int なので、今回はキャストは要りません。空配列を渡したときは、流れる要素が 1 つも無いので sum() の結果が 0 になります。長さを調べる if は不要です。
要件
Arrays.stream(arr)でint[]をIntStreamに変換することmap(x -> x * x)を使って各要素を 2 乗する Stream の中間操作を使うこと (生の for ループで合計するのは NG)- 終端操作
sum()を呼んでintの合計をreturnすること
入出力例
squareSum([1,2,3]) → 14
squareSum([]) → 0
squareSum([5]) → 25
squareSum([2,4]) → 20
squareSum([0,0,0]) → 0