web-dev-qa-db-ja.com

Javaグッドプラクティスで可能な限りLambda式を使用していますか?

Java 8で導入されたラムダ式を最近習得しました。関数型インターフェイスを使用しているときはいつでも、常に実装するクラスを作成する代わりにラムダ式を使用する傾向があります。機能的なインターフェース。

これは良い習慣と考えられますか?または、機能インターフェースにLambdaを使用することが適切ではないという状況はありますか?

52
SteelToe

ラムダを使用しないことを検討すべきいくつかの基準があります。

  • サイズラムダが大きくなるほど、それを取り巻くロジックをたどることが難しくなります。
  • Repetition分散した非常に単純なラムダを繰り返してもかまいませんが、繰り返しロジックには名前付き関数を作成することをお勧めします。
  • Naming意味のある名前を思い付くことができる場合は、コードをより明確にするため、代わりにそれを使用する必要があります。 priceIsOver100のような名前ではありません。 x -> x.price > 100はその名前と同じくらい明確です。条件の長いリストを置き換えるisEligibleVoterのような名前を意味します。
  • ネスティングネストされたラムダは本当に本当に読みにくいです。

行き過ぎないでください。ソフトウェアは簡単に変更できることを覚えておいてください。疑問がある場合は、両方に書き、どちらが読みやすいかを確認してください。

117
Karl Bielefeldt

場合によります。異なる場所で同じラムダを使用していることに気付いたときはいつでも、インターフェイスを実装するクラスの実装を検討する必要があります。しかし、匿名の内部クラスを使用した場合は、ラムダの方がはるかに優れていると思います。

14
Tohnmeister

私はカールビーレフェルトの答えを支持しますが、簡単な補足を提供したいと思います。

  • デバッグ一部のIDEはラムダ内のスコープとの闘い、およびラムダのコンテキスト内でメンバー変数を表示するのに苦労します。うまくいけば、この状況は将来的には変化しますが、ラムダが散らかっているときに他の誰かのコードを維持するのは面倒です。
14
Jolleyboy

包含スコープのローカル変数へのアクセス

承認された カールビーレフェルトの回答 が正しいです。もう1つ区別を付けることができます。

  • 範囲

クラス内のメソッド内にネストされたラムダコードは、そのメソッドとクラス内で見つかったすべての効果的な変数- final にアクセスできます。

関数インターフェイスを実装するクラスを作成しても、呼び出し元のコードの状態に直接アクセスすることはできません。

引用するJavaチュートリアル (私の強調)):

ローカルクラスと匿名クラスのように、ラムダ式は変数をキャプチャできます。それらは同じ外側のスコープのローカル変数へのアクセスを持っています。ただし、ローカルクラスや匿名クラスとは異なり、ラムダ式にはシャドウイングの問題はありません(詳細については、シャドウイングを参照してください)。ラムダ式はレキシカルにスコープされます。つまり、スーパータイプから名前を継承したり、新しいレベルのスコープを導入したりすることはありません。ラムダ式の宣言は、囲み環境と同じように解釈されます。

したがって、長いコードを引き出して名前を付けることには利点がありますが、それを囲んでいるメソッドとクラスの状態に直接アクセスする単純さと比較検討する必要があります。

見る:

6
Basil Bourque

これは一見の価値があるかもしれませんが、他の回答で行われた他のすべての優れた点に加えて、

メソッド参照を優先可能な場合。比較:

employees.stream()
         .map(Employee::getName)
         .forEach(System.out::println);

versus

employees.stream()
         .map(employee -> employee.getName())
         .forEach(employeeName -> System.out.println(employeeName));

メソッド参照を使用すると、ラムダの引数に名前を付ける必要がなくなります。これは、通常、冗長であるか、exのような遅延名につながります。

4
Matt McHenry

Matt McHenryの答えに基づいて、ラムダとメソッド参照の間に関係があり、ラムダを一連のメソッド参照として書き直すことができます。例えば:

employees.stream()
         .forEach(employeeName -> System.out.println(employee.getName()));

employees.stream()
         .map(Employee::getName)
         .forEach(System.out::println);
0
LaFayette