java8特性

# ラムダ式

## ラムダ式はなぜ必要なのか？
```java:従来の書き方
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("従来の書き方：この行為を実行します。");
    }
}).start();
```

### 問題点は？
1. コードから意図が正しく伝わらない。  
Threadに渡したいのは、行為(メソッド)なのに、もの(インスタンス)を渡している。
2. コードがシンプルでない、可読性がよくない。  
SYstem.out.println()以外は、冗長コードである。

```java:ラムダ式
new Thread(() -> {
    System.out.println("別スレッドで行為1を実行します。");
}).start();
```
### ラムダ式の利点
1. コードから意図が伝わる。
Threadには行為(メソッド)を渡している。
2. 冗長コードは排除された。

## ラムダ式の変数は実質値参照である
```java
public class Demo2 {
    public static void main(String[] args) {
        String outer = "outerString";

        // 値参照
        Runnable runnable = () -> System.out.println("外部変数 : " + outer) ;
        demo3Sub(runnable);
    }

    private static void demo3Sub(Runnable runnable) {
        runnable.run();
    }
}
```
```出力
外部変数 : outerString
```

### 変数outerに注目
1. 変数`outer`をfinalに宣言しなくても、エラーにはならない。
2. 変数`out`に値を代入するとエラーなる。__実質値参照__になる。

## ラムダ式の書き方
```java
// 引数なし
Runnable runnable1 = () -> System.out.println("引数なし");
runnable1.run();

// 複数ステートメント
Runnable runnable2 = () -> {
    System.out.println("引数なし");
    System.out.println("複数ステートメント");
};
runnable2.run();

// 引数一つ
Consumer<String> consumer = arg1 -> System.out.println("引数一つ : " + arg1);
consumer.accept("value1");

// 引数二つ & 型推理
BinaryOperator<String> binaryOperator1 = (arg1, arg2) -> "引数二つ連結：" + arg1 + arg2;
System.out.println(binaryOperator1.apply("param1", "param2"));

// 引数二つ & 型指定
BinaryOperator<Long> binaryOperator2 = (Long arg1, Long arg2) -> arg1 + arg2;
System.out.println(binaryOperator2.apply(10L, 20L));
```

## jdk提供の@FunctionalInterface
|     IF     |      引数    |   戻り値|
|:-----------|:-----------:|:-------:|
|Predicate<T> |  T   |  boolean|
|Consumer<T>  |  T   |  void|
|Function<T,R>|  T   |  R|
|Supplier<T>  |  None|  T|
|UnaryOperator<T>  |  T      | T|
|BinaryOperator<T> |  (T, T) | T|

# StreamAPI
集合に対するAPIを提供する。

1. 操作の抽象度が高くなるらしい
2. 並列実行に向いているらしい
3. ラムダ式との併用でコードの可読性があがるらしい
4. for文のようなテンプレートっぽいコードが減るらしい

## 中間操作と終端操作
```java:中間操作(filter())
Stream.of("java", "spring", "c#")       
        .filter(    
                book -> {
                    System.out.println("4文字以上書籍名:" + book);
                    return book.length() >= 4;
                });
```
`System.out.println("4文字以上書籍名:" + book);`は実行されない。

```java:終端操作(count())
Stream.of("java", "spring", "c#")
        .filter(
                book -> {
                    System.out.println("4文字超え書籍名:" + book);
                    return book.length() >= 4;
                })
        .count();
```
```出力
書籍名:java
書籍名:spring
書籍名:c#
```
1. 中間操作では、集合走査は行わない。  
    - Builderパターンと似ている部分がある。(https://qiita.com/disc99/items/840cf9936687f97a482b)  
    - 集合に対する属性を設定(中間操作)した後に、どう実行（終端操作）したほうが一番効率よい方法を決めれるから。
2. __中間操作と終端操作は、戻り値で判別できる。__　(本当に？？)  
    - Stream<T> filter(Predicate<? super T> predicate); -> Streamを返すのは中間操作  
    - long count(); -> voidかStream以外を返すのは終端操作  

## よく使うAPI
- __collect__ : streamからList,Map,Setを生成する  
<R, A> R collect(Collector<? super T, A, R> collector);

```java:List取得
List<String> collected = Stream.of("a", "b", "c")
        .collect(Collectors.toList());
// toSet(), toMap()
```

- __map__ : TをRに変換する
<R> Stream<R> __map__(Function<? super T, ? extends R> mapper)

```java:大文字変換
List<String> uppers = Stream.of("a", "b", "hello")
        .map(string -> string.toUpperCase())
        .collect(Collectors.toList());
System.out.println(uppers);
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104977/ecfbcc43-e2ee-2933-cc20-0d5d969da80b.png)


- __filter__ ：フィルター  
Stream<T> __filter__(Predicate<? super T> predicate);

```java:数字から始まる文字列検索
List<String> beginningWithNumbers = Stream.of("1a1", "1abc", "abc1")
        .filter(value -> isDigit(value.charAt(0)))
        .collect(Collectors.toList());
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104977/d0e62eb2-a607-10ee-c5c2-a07c8182b5f7.png)

- __flatMap__ : 複数streamを一つにする  
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

```java:一つのListにする
List<Integer> together = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4))
        .flatMap(numbers -> numbers.stream())
        .collect(Collectors.toList());
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104977/769dccdc-6a1c-e2f6-8dbb-bcdd21a7453c.png)


- __max__ and __min__ : 最大、最小  
Optional<T> max(Comparator<? super T> comparator)  　
Optional<T> min(Comparator<? super T> comparator)  

```最大値と最小値
Integer max = Stream.of(1, 2, 5, 3, 4)
        .max(Comparator.comparing(num -> num.intValue()))
        .get();

Integer min = Stream.of(1, 2, 5, 3, 4)
        .min(Comparator.comparing(num -> num.intValue()))
        .get();
```

- __reduce__ :  streamから一つの値を生成
T reduce(T identity, BinaryOperator<T> accumulator);

```java:合計を取得する
int summary = Stream.of(1, 2, 3, 4)
        .reduce(0, (acc, element) -> acc + element);

// 合計は、summaryStatistics()が妥当だけど。
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/104977/e27c06f8-1f35-0b15-aa67-4e97e900af8f.png)


## StreamAPIによるリファクター
例：複数のアルバムから曲の長さが３分以上の曲名を取得する。

```java:アルバム
import java.util.List;

public class Album {
    private String musician; // 歌手
    private List<Track> trackList;  // 曲リスト

    public Album(String musician, List<Track> trackList) {
        this.musician = musician;
        this.trackList = trackList;
    }

    public String getMusician() {
        return musician;
    }

    public List<Track> getTrackList() {
        return trackList;
    }
}
```
```java:曲
public class Track {
    private String name;
    private long length;

    public Track(String name, long length) {
        this.name = name;
        this.length = length;
    }

    public String getName() {
        return name;
    }

    public long getLength() {
        return length;
    }
}
```
```java:アルバム、曲生成メソッド
// アルバム生成
public static List<Album> makeAlbumList(int albumSize, int trackSize) {
    List<Album> albumList = new ArrayList<>();
    for (int i = 0; i < albumSize; i++) {
        Album album = new Album("musician:" + RandomStringUtils.randomAlphabetic(10), makeTrackList(trackSize));
        albumList.add(album);
    }
    return albumList;
}
// 曲生成
private static List<Track> makeTrackList(int trackSize) {
    List<Track> trackList = new ArrayList<>();
    Random random = new Random(System.currentTimeMillis());
    for (int i = 0; i < trackSize; i++) {
        Track track = new Track("track : " + RandomStringUtils.randomAlphabetic(10), random.nextInt(5) + 1);
        trackList.add(track);
    }
    return trackList;
}
```
```java:リファクタ対象である従来のコード
// アルバムリスト生成
List<Album> albumList = makeAlbumList(5,5);
// 検索結果
List<String> result = new ArrayList<>();
// 1. アルバムリストを走査
for (Album album : albumList) {
    // 2. 曲リストを走査
    for (Track track : album.getTrackList()) {
        // 3. 曲の長さ判定
        if (track.getLength() >= 3) {
            // 4. 曲名保存
            result.add(track.getName());
        }
    }
}
```
二重for文、さらにif文 -> リファクター対象を選ぶ際の__「 不吉な匂い」__ってやつですね。

```java:一回目リファクタ
List<String> result1 = new ArrayList<>();
albumList.stream()                                  // 1. StreamAPI取得
    .forEach(                                       // 2. 曲リストを走査
        album -> {
            album.getTrackList().forEach(                // 3. 曲リストを走査
                track -> {
                    if (track.getLength() >= 3) {        // 4. 曲長さ判定
                        result1.add(track.getName());    // 5. 曲名保存
                    }
                }
            );
        }
    );
```

おや、StreamAPIを使ったけど、なんだか処理ステップ？？？可読性？？？の状態。  
判定部分は__filter__, 曲から曲名取得は__map__が使えるね。

```java:二回目リファクタ
List<String> result2 = new ArrayList<>();
albumList.stream()
    .forEach(album -> {
        album.getTrackList().stream()
            .filter(track -> track.getLength() >= 3)
            .map(track -> track.getName())
            .forEach(trackName -> result2.add(trackName))
    });
```

インデントから見ても２階層以上はあるように見えるね。
アルバム毎の曲リストは__flatMap__を使って、一つのStreamにすれば、__foreach__がなくなるのでは？

```java:三回目リファクタ
List<String> result3 = new ArrayList<>();
albumList.stream()
    .flatMap(album -> album.getTrackList().stream())
    .filter(track -> track.getLength() >= 3)
    .map(track -> track.getName())
    .forEach(trackName -> result3.add(trackName));
```

最後の__forEach__、かつ結果リストに詰める処理がを綺麗にする。
__collect__の出番。

```java:四回目リファクタ
List<String> result4 = albumList.stream()
    .flatMap(album -> album.getTrackList().stream())  // 1. 全ての曲
    .filter(track -> track.getLength() >= 3)          // 2. 曲長さで絞る
    .map(track -> track.getName())                    // 3. 名前だけほしい
    .collect(Collectors.toList());                    // 4. 結果はListにする
```

リファクター前と４回目リファクターで比較すると、大分綺麗になったようだ。

## StreamAPI(ラムダ式の意義)

リファクタ前のコードは、__「どう変えるか？」__に注力している。  

1. アルバムを走査する
2. 曲リストを走査する
3. 長さを判定する
4. 曲から曲名を取得する


リファクタ後のコードは、__「何に変えるか？」__に注力している。

1. flatMap : 複数の曲リストを一つのリストに変える
2. filter : 曲長さが3分以上のリストに変える
3. map : 曲を曲名に変える
4. collect : StreamをListに変える

ラムダ式を使うことの意義は、
1. 意図が正しく伝わる。
2. 副作用の少ないコードがかける。

* リファクタ前の`List<String> result`の状態が変わるので、副作用があると言える
* ラムダ式で外部状態の変更はコンパイルエラーになる、__実質final__。  
なので、自然と副作用の少ないコードが書ける。

### Streamの順序

```java:順序が保障される
List<Integer> expectedList = Arrays.asList(2, 1, 3, 4);
// 100回Stream操作
for (int i = 0; i < 100; i++) {
    List<Integer> actualList = expectedList.stream()
        .map(ele -> ele)
        .collect(Collectors.toList());
    assertEquals(expectedList, actualList);
}
```

```java:順序が保障されない
List<Integer> expectedList = Arrays.asList(2, 1, 3, 4);
Set<Integer> expectedSet = new HashSet<>(Arrays.asList(2, 1, 3, 4));
// 100回Stream操作
for (int i = 0; i < 100; i++) {
    List<Integer> actualList = expectedSet.stream()
        .map(ele -> ele)
        .collect(Collectors.toList());
    assertEquals(expectedList, actualList);
}
```

Stream操作元が順序を保障するものであれば(例：List)順序が保障される。
Stream操作元が順序を保障しないものであれば(例：Set)順序が保障されない。

- sorted() : 順序をつける
- unordered() : 順序を消す

多くの処理(filter,map,reduce等)では順序あり(sorted)が処理効率がよいが、
一部の処理では順序なし(unordered())が効率よくなる。

# ライブラリ

## 基本型(int, double, long)
基本型よりオブジェクトがメモリ使用量が大きいのは明白。
またジェネリックで基本型は使えないので、boxing,unboxingが必要となりリソースが使われる。

StreamAPIは基本型のint, double, longへ特殊な方法を提供して、効率よく処理できるようにしている。

- mapToInt
- mapToDouble
- mapToLong

サンプルでパフォーマンス比較してみる。

```java:基本型変換(autoboxing)
// 曲は10000000のアルバム
Album album = Refactor.makeAlbumList(1, 10000000).get(0); // 自作
long start;
start = System.currentTimeMillis();
Long summary1 =
    album.getTrackList().stream()
        .map(track -> track.getLength())
        .reduce(0L, (acc, element) -> acc + element);
System.out.println("総長さ　 : " + summary1);
System.out.println("auto boxing 消費時間 : " + (System.currentTimeMillis() - start));
```
```出力
総長さ　 : 16127232
auto boxing 消費時間 : 1582
```

```java:toMapXxx使用
start = System.currentTimeMillis();
Long summary2 =
    album.getTrackList().stream()
    .mapToLong(track -> track.getLength())
    .reduce(0, (acc, element) -> acc + element);
System.out.println("総長さ　 : " + summary2);
System.out.println("mapToLong消費時間 : " + (System.currentTimeMillis() - start));
```
```出力
総長さ　 : 16127232
mapToLong消費時間 : 54
```

- 30分の1になったね！

## interfaceのdefalutメソッド
interfaceが実装を持つこと。

```java:親
public interface Parent {
    public void message(String body);

    public default void hey() {
        System.out.println("Parent: hey!");
    }
}
```

```java:親実装
public class ParentImpl implements Parent {
    @Override
    public void message(String body) {
        System.out.println("Parent:message");
    }
}
```
```java:テスト
Parent parent = new ParentImpl();
parent.hey();
```
```java:出力
Parent: hey!
```

さらに、

```java:親を継承した子
public interface Child extends Parent {
    @Override
    default void hey() {
        System.out.println("Child: hey!");
    }
}
```
```java:子実装
public class ChildImpl implements Child {
    @Override
    public void message(String body) {
        System.out.println("Child:message");
    }
}
```
```java:テスト
Parent parent = new ParentImpl();
parent.hey();
Child child = new ChildImpl();
child.hey();
```
```出力
Parent: hey!
Child: hey!
```

1. IFのdefalutメソッドは実装であり、override必須ではない
2. defalutメソッドをoverrideすることはできる。

### それでは、なぜdefalutが必要なのか？
java8の特性(StreamAPI等)により、既存jdkのライブラリを修正した。
たとえば、Collection#stream()。
サードパーティでCollectionを実装した場合、java8の環境ではコンパイルできなくなる。
すでにコンパイル済みのであっても実行環境で動かない。

```java:java8のCollection実装
// 略

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

default Stream<E> parallelStream() {
    return StreamSupport.stream(spliterator(), true);
}

// 略
```

defalutの実装により、この問題が解消される。
java1から7までのコードがjava8でも動くように
__互換性__を保つために追加されたと言える。


### defalutメソッドと多重継承
javaのインタフェースは多重継承できて、継承元で同じdefalutメソッド実装した場合、コンパイルエラーが発生する。
「class Musical Carriage inherits unrelated defaults for rock() from types Carriage and Jukebox」

解決策 : IF名.super.defalutメソッド
複数親の内、どれを自分のdefalutにするかを決めてあげる。

```java:superキーワード
public interface Child extends Parent, AnotherParent {
    @Override
    default void hey() {
        Parent.super.hey();
    }
}
```

## interfaceの静的メソッド
```java:例：StreamAPI.of()
public static<T> Stream<T> of(T... values) {
    return Arrays.stream(values);
}
```
オブジェクト指向上、ある振る舞いがクラス、もしくはインターフェースに所属すべきだが、
今まではユーティルクラスへ入れたり(java7のObjects)した。

java8のinterfaceの静的メソッドの追加により、あるべき姿になった感じ？

## Optional
nullの代わりに用意された新しいデータ型である。 NullObjectパターンっぽいやつかな？

- Optional生成

```java:of,empty,ofNullable
Optional op1 = Optional.of("value1");
Optional op2 = Optional.empty();
Optional op3 = Optional.ofNullable(null);
```

- Optional値存在チェック
 
```java:isPresent
assertTrue(op1.isPresent());
assertFalse(op2.isPresent());
assertFalse(op3.isPresent());
```

- Optional値取得

```java:get
assertEquals("value1", op1.get());
```
emptyに対してgetを行う場合、__java.util.NoSuchElementException__が発生する。
emptyの場合、isPresentより、代替値を使うのお勧め。

- Optionalのempty代替値

```java:orElse,orElseGet,orElseThrow
Optional op4 = Optional.empty();
assertEquals("get else value", op4.orElse("get else value"));

Optional op5 = Optional.ofNullable(null);
assertEquals("get lambda value", op5.orElseGet(() -> "get lambda value"));

Optional op6 = Optional.ofNullable(null);
try {
    op5.orElseThrow(() -> new IOException("IO例外発生させる"));
} catch (Throwable throwable) {
    assertEquals("IO例外発生させる",throwable.getMessage());
}
```

orElse, orElseGet, orElseThrowは三項演算子っぽいものね。

## メソッド参照
java8が提供する新しい文法で、メソッド呼び出しのために使用する。
__文法 : Classname::methodName__

- 引数を提供する必要がなく、コンパイラーが探してくれる
- ()はいらない。ここで実行するのではないので。

```java:メソッド参照にする
Long summary =
    album.getTrackList().stream()
//      .map(track -> track.getLength())
        .map(Track::getLength)
        .reduce(0L, (acc, element) -> acc + element);
```

```java:newする
// new String[]{}
String[]::new
```

# Collector(結果収集)
Streamの最終的結果を収集する役割。
- 内部ではreduceメソッドである。
- カスタムCollector定義も可能。

## 集合を取得する(List, Set, TreeSetなどなど)

```java
// アルバム
Album album = Refactor.makeAlbumList(1, 5).get(0);

// toList
List<String> trackNameList = album.getTrackList()
    .stream()
    .map(Track::getName)
    .collect(Collectors.toList());
System.out.println("Listへ : " + trackNameList);

// toSet
Set<String> trackNameSet = album.getTrackList()
    .stream()
    .map(Track::getName)
    .collect(Collectors.toSet());
System.out.println("Setへ : " + trackNameSet);

// toTreeSet
TreeSet<String> trackNameTreeSet = album.getTrackList()
    .stream()
    .map(Track::getName)
    .collect(Collectors.toCollection(TreeSet::new));
System.out.println("TreeSetへ : " + trackNameTreeSet);
```

## 一つの値を取得する

```java
// アルバム
Album album = Refactor.makeAlbumList(1, 10).get(0);

// もっとも長い曲を取得する
Optional<Track> longest =
    album.getTrackList().stream()
        // Stream#maxを使えとIntelliJが言うけど
        .collect(Collectors.maxBy(Comparator.comparing(Track::getLength)));

System.out.println("最大長さ曲名: " + longest.get().getName());
System.out.println("長さ:" + longest.get().getLength());

// 平均取得
Double average =
    album.getTrackList().stream()
        .collect(Collectors.averagingLong(Track::getLength));
System.out.println("平均長さ:" + average);
```
```java:結果
最大長さ曲名: track : rSAGmQLuXr
長さ:5
平均長さ:3.2
```

## 2分割する

```java
// アルバム
Album album = Refactor.makeAlbumList(1, 10).get(0);

// 3分を基準に分割
Map<Boolean, List<Track>> partition =
    album.getTrackList().stream()
        .collect(Collectors.partitioningBy(track -> track.getLength() >= 3));

System.out.println("3分以上:");
partition.get(Boolean.TRUE).stream()
    .forEach(track -> System.out.println("曲名: " + track.getName() + " 長さ:" + track.getLength()));

System.out.println("3分未満:");
partition.get(Boolean.FALSE).stream()
    .forEach(track -> System.out.println("曲名: " + track.getName() + " 長さ:" + track.getLength()));
```
```java:結果
3分以上:
曲名: track : BxQyeGMepu 長さ:4
曲名: track : IJlOMSUSgK 長さ:4
曲名: track : WHJxMIurcv 長さ:4
曲名: track : MfybYuUJqq 長さ:4
曲名: track : lDtgbWaKBw 長さ:3
3分未満:
曲名: track : mLjTdpGqlz 長さ:2
曲名: track : UTZhgFxcNR 長さ:2
曲名: track : rVMIzMDDTo 長さ:1
曲名: track : xVEvTXDKqe 長さ:1
曲名: track : pJBrUfiCva 長さ:1
```
## 文字列を取得する

```java
Album album = Refactor.makeAlbumList(1, 10).get(0);
String result =
    album.getTrackList().stream()
        .map(Track::getName)
        .collect(Collectors.joining(", ", "[", "]"));
System.out.println(result);
```
```java:結果
[track : qCGRMYQWRz, track : xmeEorPUSP, track : qUFzXrlicZ, track : iBiEXwufrQ, track : zxDIcXnCYr]
```
## グルーピングする

```java
// アルバム
Album album = Refactor.makeAlbumList(1, 10).get(0);
Map<Long, List<Track>> grouping =
    album.getTrackList().stream()
        .collect(Collectors.groupingBy(Track::getLength)); // 長さでグルーピングする

// 長さ毎の曲数を取得する
Map<Long, Integer> numberOfTrack = new HashMap<>();
for (Map.Entry<Long, List<Track>> entry : grouping.entrySet()) {
    numberOfTrack.put(entry.getKey(), entry.getValue().size());
}
System.out.println(numberOfTrack);
```
```java:結果
{1=1, 2=2, 4=3, 5=4}
```

## Collector組み合わせ
上記グルーピングの場合、まず長さでグルーピング、その後for文でグルーピングしている。
これはCollector組み合わせの組み合わせで解決できる。

```java:Collectorの組み合わせ
// アルバム
Album album = Refactor.makeAlbumList(1, 10).get(0);
Map<Long, Long> grouping =
    album.getTrackList().stream()
        .collect(
            Collectors.groupingBy(
                Track::getLength,         // 長さでgrouping
                Collectors.counting()     // groupingした結果に対して、countする
            )); // 長さでグルーピングする
System.out.println(grouping);
```
```java:結果
{1=1, 2=2, 4=3, 5=4}
```

組み合わせ用はほかにも色々(mappingとか)あるが、割愛。

# Streamの平列処理
簡単に言えば、複数コアに仕事させるってこと。
下記メソッドで簡単にパラレル実行可能になる。

- parallel()  
- parallelStream()
 
## parallelStream
```java:総長さ取得
// アルバム
Album album = Refactor.makeAlbumList(1, 10000000).get(0);

long start = System.currentTimeMillis();
long summary =
    album.getTrackList().stream()
        .mapToLong(Track::getLength)
        .sum();

System.out.println("シングル処理時間: " + (System.currentTimeMillis() - start));
System.out.println("総長さ: " + summary);

start = System.currentTimeMillis();
long summaryWithParallel =
    album.getTrackList().parallelStream()
        .mapToLong(Track::getLength)
        .sum();

System.out.println("パラ処理時間: " + (System.currentTimeMillis() - start));
System.out.println("総長さ: " + summaryWithParallel);
```
```出力
シングル処理時間: 109
総長さ: 29336172
パラ処理時間: 62
総長さ: 29336172
```

## 平列処理に影響する要素
1. データの大きさ  
fork/joinの処理があるため、小さいデータの場合、逆に遅くなる。
2. 元データの種類
分割しやすいデータほど処理が早い
    - ArrayList, Array, IntStream.Rangeは分割し易いので、良い
    - HashSet,TreeSet等は分割に向いてないケースもあるので、普通
    - LinkedList,BufferedReader.lines等は分割が難しいので、悪い
3. boxing
基本型が性能よい。
4. コア数
多いほうがいいね、逆にシングルコアだとパラの意味がないね
5. ユニット処理時間
ユニット処理が長いほど、平列でよい性能が期待される。

## Arraysに新規追加した機能
### parallelSetAll : 配列を更新する
```java:配列更新
int[] values = new int[10];

int val = 10;
Arrays.parallelSetAll(values, i -> i);

System.out.println(
    Arrays.stream(values)
        .mapToObj(String::valueOf)
        .collect(Collectors.joining(", ", "[", "]"))
);
```
```出力
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```

### parallelSort : ソートする
```java:ソート
Integer[] sums = {1, 2, 3, 4};

Arrays.parallelPrefix(sums, Integer::sum);

System.out.println(
    Arrays.stream(sums)
        .mapToInt(Integer::intValue)
        .mapToObj(String::valueOf)
        .collect(Collectors.joining(", ", "[", "]"))
);
```
```出力
[1, 2, 3, 4]
```
### parallelPrefix:BinaryOperatorのセット
```java：
Integer[] sums = {1, 2, 3, 4};

Arrays.parallelPrefix(sums, Integer::sum);

System.out.println(
    Arrays.stream(sums)
        .mapToInt(Integer::intValue)
        .mapToObj(String::valueOf)
        .collect(Collectors.joining(", ", "[", "]"))
);
```
```出力
[1, 3, 6, 10]
```

# ラムダ式のデバックと単体テスト
## デバッグ

```java:アルバムから長さ3分以上の曲名を取得する
// アルバムリスト生成
Album album = makeAlbumList(1, 5).get(0);

List<String> trackNameList1 = album.getTrackList().stream()
    .filter(track -> track.getLength() >= 3)
    .map(Track::getName)
    .collect(Collectors.<String>toList());
```

filter,mapは中間操作であるため、stream操作は行わない。
終端操作であるcollectをコメントアウトして、forEachで確認してみよう！

```java:まずは、filterした結果を標準出力してみる
album.getTrackList().stream()
    .filter(track -> track.getLength() >= 3)
    .forEach(track -> System.out.println("曲名 : " + track.getName() + " 長さ : " + track.getLength()));
//      .map(Track::getName)
//      .collect(Collectors.<String>toList());
```
```java:出力
曲名 : track : pQPTCFWDly 長さ : 4
曲名 : track : qXpziYuSHi 長さ : 4
曲名 : track : TFXgoRODAm 長さ : 3
```

```java:mapした結果を標準出力してみる
album.getTrackList().stream()
    .filter(track -> track.getLength() >= 3)
    .map(Track::getName)
    .forEach(trackName -> System.out.println("曲名 : " + trackName));
//      .collect(Collectors.<String>toList());
```
```java:出力
曲名 : track : pQPTCFWDly
曲名 : track : qXpziYuSHi
曲名 : track : TFXgoRODAm
```
デバックのための、実装をコメントアウトしたり、なんとかくいけてない！

### peek()の出番
```java:peek()を確認したデバックした箇所に入れる
List<String> trackNameList2 = album.getTrackList().stream()
    .filter(track -> track.getLength() >= 3)
    .peek(track -> System.out.println("曲名 : " + track.getName() + " 長さ : " + track.getLength()))
    .map(Track::getName)
    .peek(trackName -> System.out.println("曲名 : " + trackName))
    .collect(Collectors.<String>toList());
```
```出力
曲名 : track : npECfTvxoy 長さ : 5
曲名 : track : npECfTvxoy
曲名 : track : RDKLzmREzw 長さ : 4
曲名 : track : RDKLzmREzw
曲名 : track : DGZiRdurZQ 長さ : 3
曲名 : track : DGZiRdurZQ
```

```java:peekを使って、log出力
Logger logger = Logger.getLogger(Demo6.class);
List<String> trackNameList3 = album.getTrackList().stream()
    .filter(track -> track.getLength() >= 3)
    .peek(track -> logger.debug("曲名 : " + track.getName() + " 長さ : " + track.getLength())) // logger
    .map(Track::getName)
    .peek(trackName -> logger.debug("曲名 : " + trackName))                                   // logger
    .collect(Collectors.<String>toList());
```

## ラムダ式とmock(with mockito)
```java
List<String> list = mock(List.class);

// 既存の書き方
when(list.size()).thenAnswer(new Answer<Object>() {
    @Override
    public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
        System.out.println("既存：値を返却する前の処理");
        return 3;
    }
});

// ラムダ式
when(list.size()).thenAnswer(invocationOnMock -> {
    System.out.println("ラムダ：値を返却する前の処理");
    return 3;
});
assertEquals(3, list.size());
```
```java:出力
既存：値を返却する前の処理
ラムダ：値を返却する前の処理
```

ラムダ式を使えるのは、thenAnswerの引数の、AnswerがFunctional interfaceであるからだ。

```java:Answer.java
public interface Answer<T> {
    T answer(InvocationOnMock var1) throws Throwable;
}
```

参考書籍：Java-Lambdas-Functional-Programming-Masses