Collection.stream().map()からの拒絶を経て


実装したかったこと

Listの要素のクラスから2つのStringを抽出し、
その2つのStringを格納したPairのListを生成する。

Stream使えばいけそう^^

ビルドできない

List<Hogehoge> list;

list
.stream()
.map(Pair.of(Hogehoge::getFoo, Hogehoge::getBar)) 
// ↑↑ Object is not a functional interface ↑↑
.collect(Collectors.toList())

ん!?

Functional Interface !?

関数型インタフェースは、
関数メソッドと呼ばれる単一の抽象メソッドが含まれているインターフェース
ref . パッケージjava.util.function
ref . Java8 in Action

加えて...

ラムダ式を使うことで、
関数型インターフェースの抽象メソッドの実装をインラインで明示でき、
その全体式を関数型インターフェースのインスタンスとして扱うことができる。
(つまるところ、関数型インターフェースの実装となる)
ref . Java8 in Action

なるほど。
ここで、以下の2つのことを理解。
1. 関数型インターフェースは、単一の抽象メソッドが含まれているインターフェース
2. ラムダ式により、関数型インターフェースを実装可能

そもそもStream.map()の定義って ^^;

Stream map(Function<? super T,? extends R> mapper)
パラメータ: mapper
- 各要素に適用する非干渉でステートレスな関数
インタフェースStream<T>

引数mapperの型であるFunctionは、
単一抽象メソッドapplyを持つ「関数型インターフェース」
ref. Interface Function<T,R>

本題に戻って

関数型インターフェースであるFunctionをラムダ式で実装して、
mapに渡せばよいことがわかった。

List<Hogehoge> list;
Function<Hogehoge,Pair<String,String>> makePairsFromObj = 
hoge -> Pair.of(hoge.getFoo(), hoge.getBar());

List<Pair<String, String>> pList = list
                .stream()
                //.map(makePairFromObj::apply) 
                .map(makePairFromObj) // Function型の変数を渡せばよい by @swordone 
                .collect(Collectors.toList());

もしくは、直接ラムダ式を渡す(@swordoneさんからの指摘)

List<Hogehoge> list;

List<Pair<String, String>> pList = list
                .stream()
                .map(hoge -> Pair.of(hoge.getFoo(), hoge.getBar()))
                .collect(Collectors.toList());

\(^o^)/