20

近くの Java (J8) にラムダが間もなく登場すると聞きました。いくつかのブログで、それらがどのように見えるかの例を見つけました:

SoccerService soccerService = (teamA, teamB) -> {
    SoccerResult result = null;
    if (teamA == teamB) {
        result = SoccerResult.DRAW;
    }
    else if(teamA < teamB) {
        result = SoccerResult.LOST;
    }
    else {
        result = SoccerResult.WON;
    }

    return result;
};

だからすぐに:

  • どこにteamA入力teamBされていますか?それともそうではありませんか(ジェネリックの奇妙な形のように)?
  • ラムダはクロージャーの一種ですか、それともその逆ですか?
  • これにより、典型的な匿名関数よりもどのような利点が得られますか?
4

3 に答える 3

16

ラムダ式は、ターゲット インターフェイスを実装するための単なる構文糖衣です。これは、ラムダ式を介して特定のメソッドをインターフェイスに実装することを意味します。コンパイラはインターフェイス内のパラメーターの型を推測できるため、ラムダ式でパラメーターを明示的に定義する必要はありません。

例えば:

Comparator<String> c = (s1, s2) -> s1.compareToIgnoreCase(s2);

この式では、ラムダ式は明らかComparatorに文字列の a を実装しているため、これはラムダ式が を実装するための構文糖衣であることを意味しますcompare(String, String)

したがって、コンパイラは安全にs1and s2isの型を想定できStringます。

ターゲット インターフェイスの型は、コンパイラがラムダ パラメーターの実際の型を判断するために必要なすべての情報を提供します。

Oracle Corportion の Java 言語アーキテクトである Briant Goetz は、JDK 8 Lambdas で進行中の作業に関する記事をいくつか公開しています。あなたの質問に対する答えはそこにあると思います:

この 2 番目の記事では、ラムダ式がバイトコード レベルでどのように実装されるかを説明し、2 番目の質問の詳細を掘り下げるのに役立つかもしれません。

于 2012-07-09T22:51:35.117 に答える
15

その例の完全なバージョンについては、このページを参照してください(ただし、関連する部分は以下に示されています)。

型は、スニペットには示されていませんが、SoccerService インターフェイスと SoccerResult 列挙型から推測されます。

enum SoccerResult{
    WON, LOST, DRAW
}

interface SoccerService {
    SoccerResult getSoccerResult(Integer teamA, Integer teamB);
}

(ラムダと標準の匿名クラスの)利点は、冗長性が低下することです。

(x, y) => x + y

対次のようなもの:

new Adder()
{
  public int add(int x, int y)
  {
    return x + y;
  }
}

クロージャとラムダの違いについては、この質問を参照してください。

于 2012-07-09T22:42:17.380 に答える
9
  • teamA と teamB はどこに入力されますか? それともそうではありませんか(ジェネリックの奇妙な形のように)?

Lambda は、ジェネリック メソッド呼び出し (1.5 以降) やダイヤモンド [not an] 演算子 (1.7 以降) によく似たターゲット型付けを使用します。大まかに言えば、結果が適用される型が記述されている (または推測できる) 場所は、Single Abstract Method (SAM) の基本型の型、つまりメソッド パラメーターの型を提供するために使用されます。

1.5 での一般的なメソッドの推論の例として:

Set<Team> noTeams = Collections.emptySet(); 

1.7 のダイヤモンド演算子:

Set<Team> aTeams = new HashSet<>();

チーム、チーム、チーム、チーム、チーム、チーム。チームという言葉を言うのも大好きです。

  • ラムダはクロージャーの一種ですか、それともその逆ですか?

ラムダは、匿名の内部クラスとほぼ同じ方法でクロージャーの制限された形式ですが、いくつかのランダムな違いがあります。

アウターthisはインナーに隠れませんthis。これは、ラムダと匿名の内部クラスの同じテキストが、微妙に、しかし完全に異なることを意味する可能性があることを意味します。これにより、スタック オーバーフローは奇妙な質問で忙しくなります。

inner の不足を補うためthisに、ローカル変数に直接割り当てられた場合、その値はラムダ内でアクセスできます。IIRC(確認できましたが、しません)、匿名の内部クラスでは、ローカルはスコープ内にあり、外部スコープの変数を非表示にしますが、使用できません。インスタンス初期化子がないため、これを指定するのがはるかに簡単になると思います。

たまたまマークされていないが、マークされfinalている可能性があるローカル フィールドは、あたかも であるかのように扱われますfinal。したがって、スコープ内にはありませんが、実際に読み取ることはできます (書き込むことはできません)。

  • これにより、典型的な匿名関数よりもどのような利点が得られますか?

より簡潔な構文。それはそれについてです。

もちろん、Java 構文の残りの部分は、これまでと同じようにどうしようもなく悪いものです。

これが初期実装にあるとは思いませんが、[内部] クラスとして実装される代わりに、ラムダはメソッド ハンドルを使用できます。メソッド ハンドルのパフォーマンスは、以前の予測をやや下回っています。クラスを廃止すると、バイトコードのフットプリント、おそらく実行時のフットプリント、そして確実にクラスの読み込み時間が削減されます。ほとんどの匿名内部クラス (Serializable自明な静的イニシャライザーではない) が、特に顕著な非互換性なしに、よく考えられていないクラス ローディング メカニズムを通過しない実装が存在する可能性があります。

(隠蔽に関する用語が正しいことを願っています。)

于 2012-07-10T00:23:08.147 に答える