Java基礎練習：Stream APIでのmap()の使い方

私が最近あるコードレビューをしていてなるほどと思ったコードがありちょっと試してみたことの共有です。

# Stream APIの `map()`

これです。
https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#map-java.util.function.Function-

```
map

<R> Stream<R> map(Function<? super T,? extends R> mapper)

Returns a stream consisting of the results of applying the given function to the elements of this stream.
This is an intermediate operation.

Type Parameters:
R - The element type of the new stream

Parameters:
mapper - a non-interfering, stateless function to apply to each element

Returns:
the new stream
```

ここに書かれている通りです。 `applying the given function to the elements of this stream` ということで、引数に指定した関数をこのストリームの要素たちに行います。

## 気づき

```java:なるほどと思ったコード(一部改変)
List<HogeHoge> entityList = ...;
result = entityList.stream() //
    .map(HogeHogeDto::new) //
    .sorted() //
    .collect(Collectors.toList());
```

どうなるほどと思ったかというと、これで `entityList` の中身が `HogeHogeDto` のコンストラクタ、具体的には `HogeHogeDto(HogeHoge)` を呼び出している点です。上記ソースコードでは `HogeHogeDto::new` としか書いていないのでどのコンストラクタを呼び出すかまでは明示していませんが、型推論が働いてちゃんと `HogeHogeDto(HogeHoge)` を呼び出してくれます。

## 検証

`HogeHogeDto` クラスに、引数に `HogeHoge` を取るコンストラクタと、デフォルトコンストラクタがあった場合、ちゃんと `HogeHoge` を取るコンストラクタが呼ばれるか？
→:ok_hand:

## 追加検証

では、デフォルトコンストラクタの方を明示的に呼びたい（ストリームで渡されるものは無視したい）時はどうすればよいのでしょうか？
→明示的に無視する書き方をすることでできる。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">一方で、デフォルトコンストラクタの方を呼びたい場合、<a href="https://t.co/Z6Ycvao6kR">https://t.co/Z6Ycvao6kR</a>().map(e -&gt; new Hoge()) とすればよい。へぇへぇ。これを単に .map(new Hoge()) とするのはコンパイルエラー。</p>&mdash; fukushiw (@fukushiw) <a href="https://twitter.com/fukushiw/status/891936290387533824">2017年7月31日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

## 検証コード

```java:StreamMapTest.java
import java.util.List;
import java.util.ArrayList;

/**
 * Stream API 基礎トレーニング。
 * {@code map()} を使用した新しいリストの生成。
 */
public class StreamMapTest {
    /**
     * エントリポイント。
     * 変換前のリスト {@code List<Integer>} を元に、そのリストのサイズの分だけ
     * {@code StreamMapTest} のインスタンスを生成し、それぞれに所定の処理を行う。
     *
     * @param arguments 使用しない
     */
    public static void main(String[] arguments) {
        // テスト用に使用する変換前のリスト。
        // ここでは、StreamTest#value が int 型なので、後で代入
        // しやすくするよう List の中身は Integer としている。
        // なお0はデフォルトコンストラクタで使用するため1から
        // 値を代入している。
        List<Integer> values = new ArrayList<>();
        for (int i = 1; i <= 3; i++) {
            values.add(new Integer(i));
        }
        
        //以下確認テスト
        //（違いを見やすくするため個別のメソッドにせず
        //　main()メソッド内に列挙している）
        
        // １：intを引数に取るコンストラクタが呼ばれるパターン(1)
        System.out.println("test1------");
        values.stream() //
            .map(StreamMapTest::new) //
            .forEach(e -> System.out.println(e.getValue()));
        
        // ２：intを引数に取るコンストラクタが呼ばれるパターン(2)
        System.out.println("test2------");
        values.stream() //
            .map(e -> new StreamMapTest(e)) //
            .forEach(e -> System.out.println(e.getValue()));
        
        // ３：デフォルトコンストラクタが呼ばれるパターン
        System.out.println("test3------");
        values.stream() //
            .map(e -> new StreamMapTest()) //
            .forEach(e -> System.out.println(e.getValue()));
        
        // ４：コンパイルエラーになるパターン
        //System.out.println("test4------");
        //values.stream() //
        //    .map(new StreamMethodTest()) //
        //    .forEach(e -> System.out.println(e.getValue()));
    }
    
    /** どのようにインスタンスが作られたかをわかりやすくするために保持する値。 */
    private final int value;
    
    /**
     * デフォルトコンストラクタ。
     * インスタンス変数の値には0を設定している。
     */
    public StreamMapTest() {
        this(0);
    }
    
    /**
     * intの引数を1つ取るコンストラクタ。
     * 指定された値をインスタンス変数に代入している。
     *
     * @param value インスタンス変数に代入する値
     */
    public StreamMapTest(int value) {
        this.value = value;
    }
    
    /**
     * インスタンス変数の値を取得する。
     *
     * @return インスタンス変数の値
     */
    public int getValue() {
        return value;
    }
}
```

### 実行結果

```
C:\TEMP>java StreamMapTest
test1------
1
2
3
test2------
1
2
3
test3------
0
0
0

C:\TEMP>
```