web-dev-qa-db-ja.com

forループの代わりに「関数演算」を使用する必要があるのはなぜですか?

_for (Canvas canvas : list) {
}
_

NetBeansは、「関数型操作」を使用することを勧めています。

_list.stream().forEach((canvas) -> {
});
_

しかし、これはなぜ推奨なのか?どちらかといえば、読んで理解するのは難しいです。 stream()を呼び出してから、canvasを指定したラムダ式を使用してforEach()を呼び出しています。最初のスニペットのforループよりも優れていることはわかりません。

言うまでもなく、私は美学だけを語っています。おそらく私には見当たらない技術的な利点があります。それは何ですか?代わりに2番目の方法を使用する必要があるのはなぜですか?

42
Omega

ストリームを使用すると、受信したデータのコレクションまたはストリーム上で実行するさまざまな操作をより適切に抽象化できます。特に、要素をマップし、それらをフィルタリングして変換する必要がある場合。

あなたの例はあまり実用的ではありません。 Oracleサイトからの次のコード を検討してください。

List<Transaction> groceryTransactions = new Arraylist<>();
for(Transaction t: transactions){
  if(t.getType() == Transaction.GROCERY){
    groceryTransactions.add(t);
  }
}
Collections.sort(groceryTransactions, new Comparator(){
  public int compare(Transaction t1, Transaction t2){
    return t2.getValue().compareTo(t1.getValue());
  }
});
List<Integer> transactionIds = new ArrayList<>();
for(Transaction t: groceryTransactions){
  transactionsIds.add(t.getId());
}

ストリームを使って書くことができます:

List<Integer> transactionsIds = 
    transactions.stream()
                .filter(t -> t.getType() == Transaction.GROCERY)
                .sorted(comparing(Transaction::getValue).reversed())
                .map(Transaction::getId)
                .collect(toList());

2番目のオプションは、はるかに読みやすくなっています。ネストされたループや部分的な処理を行うさまざまなループがある場合、Streams/Lambda APIの使用には非常に適しています。

46
luboskrnac

関数型ストリーミングAPIを使用するもう1つの利点は、実装の詳細が非表示になることです。方法ではなく、何をすべきかを説明するだけです。この利点は、シングルスレッドから並列コードの実行に変更するために、実行する必要がある変更を見ると明らかになります。 .stream().parallelStream()に変更するだけです。

16
Stefan Dollase

どちらかといえば、読んで理解するのは難しいです。

それは非常に主観的です。 2番目のバージョンの方が読みやすく、理解しやすいと思います。他の言語(Ruby、Smalltalk、Clojure、Io、Ioke、Sephなど)が行う方法と一致し、理解するために必要な概念が少なくなります(最初の例は特殊な構文ですが、他の通常のメソッド呼び出しにすぎません)。

どちらかと言えば、それは親しみやすさの問題です。

13
Jörg W Mittag