2016-10-10 7 views
4

最近、私は新しいjava8機能を使いこなしています。なぜPredicate.isEqualはそのまま実装されていますか?

Stream.filterでいくつかのものを試して、私は私がisEqualメソッドの次の実装見つかっているPredicate.javaのソースに出くわした:: object -> targetRef.equals(object);:私は不思議作ら何

/** 
* Returns a predicate that tests if two arguments are equal according 
* to {@link Objects#equals(Object, Object)}. 
* 
* @param <T> the type of arguments to the predicate 
* @param targetRef the object reference with which to compare for equality, 
*    which may be {@code null} 
* @return a predicate that tests if two arguments are equal according 
* to {@link Objects#equals(Object, Object)} 
*/ 
static <T> Predicate<T> isEqual(Object targetRef) { 
    return (null == targetRef) 
      ? Objects::isNull 
      : object -> targetRef.equals(object); 
} 

は、この行でした。

たぶん私は、大規模にこれをoverthinkingていますが、私はその行がこのような: targetRef::equals;なかった理由を考えて、すぐに役立つことができませんでした:

static <T> Predicate<T> isEqual(Object targetRef) { 
    return (null == targetRef) 
      ? Objects::isNull 
      : targetRef::equals; 
} 

は、そうでない私には、ラムダの不要な創造です。

私が何かを逃していない限り、私には同じことがあります。 (彼らは同じですか?)現在の実装が選ばれた理由はありますか?それともちょうど見過ごされているか、誰も本当に気にしていない、これは信じられないほど小さなものです。

実際には、ボーナスの問題が発生すると推測されます。一方の方法でもう一方の方法を使用することに利点はありますか?ある種の(おそらく非常に小さい)パフォーマンスボーナスのように?

+2

メソッド参照は明示的ラムダと同じ研削機で終わる。両方に同じ実装方法が必要です。 –

+0

@MarkoTopolnikはい、メソッド参照を渡すのではなく、lamba(単にメソッドを呼び出すだけです)を作成することで、不要なメソッド呼び出し(ラムダ)をチェーンに追加することはありませんか? (ストリームにはたくさんのアイテムが含まれているとおそらく多く呼ばれるでしょう) –

+3

私は誰もこれに答えることはできないと思います。コードを書いた人がいると思います。そう確か。 – Tunaki

答えて

7

なぜこのように行われましたか?

純粋な推測だが、おそらく書かれたときには開発者はもっと快適で、おそらくその時には機能しなかっただろう。ライブラリはコンパイラのバグを修正している間に書かれていました。

知る方法がなく、おそらくそれを書いている人さえ覚えていないかもしれません。


あなたはメソッド参照やクロージャ構文を使用するかどうか、オブジェクトの同じ番号が(この例のように)ほとんどの場合、作成され

は、実際にはボーナス問題につながることを推測:です一方の方法で他方の方法を使用することに利点がありますか?ある種の(おそらく非常に小さい)パフォーマンスボーナスのように?

メソッドリファレンスを使用すると、メソッドコールが1つ少なくなります。これは、デフォルトでレベル数が9に制限されているため、インライン化に間接的な影響を与える可能性があります。例えば

import java.util.function.Consumer; 

public class Main { 
    public static void main(String[] args) { 
     Consumer<String> lambda = s-> printStackTrace(s); 
     lambda.accept("Defined as a lambda"); 

     Consumer<String> methodRef = Main::printStackTrace; 
     methodRef.accept("Defined as a method reference"); 
    } 


    static void printStackTrace(String description) { 
     new Throwable(description).printStackTrace(); 
    } 
} 

印刷最初のケースで

java.lang.Throwable: Defined as a lambda 
    at Main.printStackTrace(Main.java:15) 
    at Main.lambda$main$0(Main.java:6) 
    at Main.main(Main.java:7) 

java.lang.Throwable: Defined as a method reference 
    at Main.printStackTrace(Main.java:15) 
    at Main.main(Main.java:10) 

、コンパイラは、メソッドを生成した実際には1つまたは他を使用すると、よりになりprintStackTrace

を呼び出すコードを含むMain.lambda$main$0と呼ば違いは、キャプチャ(値を保存する)または非キャプチャラムダを持つことができる場合です。非キャプチャラムダは一度しか作成されません。

最初のケースで

Consumer<String> print1 = System.out::println; // creates an object each time 
Consumer<String> print2 = s->System.out.println(s); // creates an object once. 

それはへの書き込みにのPrintStreamの自身のコピーのしているとして、あなたはSystem.setOutを呼び出す場合には、この変更を無視します。

+0

ああ、あなたはその事例で私の心を吹き飛ばした!決してそれを考えなかった。 –

+1

これがなぜこのように行われたのかについての最初の質問については、答えは「私たちはほとんど知らないでしょうし、おそらく問題ではないでしょう」と思いますか? –

+1

@OlleKeldermanはlambdaのセットを想像します。これを2回追加した場合は2回、2回目の場合は1回のセットが得られます。削除しようとすると2のサイズが得られます0となる。 –

関連する問題