Java8 Lambdaまとめ その2


続きです

###### sumを使ったList内部の計算
---
```java
List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2);
intList.add(3);

System.out.println(intList);

Long count = intList.stream().mapToLong(value -> Integer.toUnsignedLong(value)).sum();

System.out.println(count);
```

最初のまとめでは説明を省略しましたが、末端処理のsumを使ってList内部の計算になります。
sumは`IntStream LongStream DoubleStream`でのみ呼び出し可能な末端処理となっていますので、中間処理完了時点で型を合わせてあげる必要がある点に注意が必要です。
`mapToXXX`はそのような形に変換してくれるので、今回はそれを使いました。

```java
List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2);
intList.add(3);

System.out.println(intList);

Long count = intList.stream().map(value -> value).mapToLong(value -> Long.valueOf(value)).sum();

System.out.println(count);
```

mapは中間処理なので、複数繋げて何回もリストの変換を行うことも可能なので、ほとんどのケースはこれでいけそうな感じがします。

##### List内部の要素を取得
---
前回はmatchする形での取得を書きましたが、今回はListの最初の要素など決まった要素を取得する形について書きます。

```java
List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2);
intList.add(3);

System.out.println(intList);

Integer count = intList.stream().findFirst().get();

System.out.println(count);
```

List内の最初の要素を取得する場合は末端処理の`findFirst`を使用します。
見つかった最初の要素を取得することが出来ます。

```java
List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2);
intList.add(3);

System.out.println(intList);

Integer count = intList.stream().findAny().get();

System.out.println(count);
```

List内のランダム要素を取得する場合は、`findAny`を使えば取れるらしいのですが、実行すると最初しか取れなかったのでちょっと良く分からないなーというしかありません。

```java
List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
intList.add(2);
intList.add(3);

System.out.println(intList);

Integer count = intList.stream().reduce((base, value) -> value).get();

System.out.println(count);
```

また、`findLast`はないので、Listの最後の要素を取りたいという場合にはfindは出来ません(なんてこったい)。
色々やり方を調べてみたのですが、`reduce`を使って、現在の値を返却し続けるというのが一番楽に実装出来そうです(300万件のList<Integer>から最後のリストを取得するという処理で性能をはかりましたが、100msもかからなかったので性能的にも問題なさそうです)

###### Streamで色々処理した後の個数を取得する
いわゆるcountを計測する方法です。
変換後の値も使用したい場合は、中間処理を終わった段階の`Stream`を保持して、末端処理をいくつも書くのが良いと思います。

```java
List<String> stringList = new ArrayList<String>();
stringList.add("japan");
stringList.add("usa");
stringList.add("england");

int count = stringList.stream().collect(Collectors.toList()).size();

System.out.println(count);
```

collectしてから`size`で取り出しても良いですが

```java
List<String> stringList = new ArrayList<String>();
stringList.add("japan");
stringList.add("usa");
stringList.add("england");

int count = stringList.stream().count();

System.out.println(count);
```

末端処理として`count`が定義されているので、これを使うと簡単に要素数が取得出来ます。

###### From Map to List
---
```
Map<String, String> stringMap = new HashMap<String, String>();
stringMap.put("japan", "japanese");
stringMap.put("usa", "english");
stringMap.put("england", "english");

List<String> list = stringMap.entrySet().stream().map(entry -> entry.getKey()).collect(Collectors.toList());

System.out.println(list);
```

`Map<K,V>`から`List<T>`への変換は簡単です。`entry`の`stream`を取得して`map`するだけです。その際の引数は`entry`になるので、そこだけ注意が必要です。
たまに`(key, value)`とかやってはまるバカがここにいます。

###### 拡張for文ではなく普通のfor文を変換する
---
```java:java7
for(int i = 0; i < 5; i++) {
    System.out.println(i);
}
```

よくある数値を使ってのループもラムダ(正確にはStream)を使うと変換することが出来ます。

```java:java8
Stream.iterate(0, i -> i + 1).limit(5).forEach(System.out::println);
```

`Stream`のClass内に`iterate`というstaticメソッドがあり、それを使うことで実現可能になります。
このメソッドは`<T>`型の無限のシーケンシャルStreamを作ってくれます。
第一引数に初期値(seed)(position 0の要素)が入ります。
第二引数は(無限に)繰り返して呼ばれ、returnした値が呼ばれた順番の要素になります。Lambdaでの引数は1個前の要素が入ってきます。
上の例ではHaskellの`[0..4]`と同様の結果を得る事が出来るStreamとなっています。

無限なので、作った後にきちんと使う所だけを抽出してあげないといけないのですが、`filter`ではうまく上の例を表現できなかったので、現状では`limit`を使って個数を制限した方が良いという結論です。他の中間処理をさせたい場合も先に`limit`してからの方が効率的だと思います。

###### 最後に
---
便利なstreamといえども、出来ない事もあるので、きちんと使えるケースを把握しておかないとたまにはまります。
そうなると勿体ないので、しっかりケースを把握していければ強力なstreamが味方になってくれて助かるのかと思ってます。
まだ新しく書くことがどんどん出てきている状況ですが、その3作るのも面倒なのである程度はここに追記されていきます。