2015-10-08 9 views
18

この質問はすでにどこかにあると思いますが、私はそれを見つけることができませんでした。lambdaを使用するために機能的なインターフェイスが必要なのはなぜですか?

それはラムダと連携するための機能のインタフェースを持つことが必要だ、なぜ私は、理解していません。次の例を考えてみましょう:

public class Test { 

    public static void main(String...args) { 
     TestInterface i =() -> System.out.println("Hans"); 
//  i = (String a) -> System.out.println(a); 

     i.hans(); 
//  i.hans("Hello"); 
    } 
} 

public interface TestInterface { 
    public void hans(); 
// public void hans(String a); 
} 

これは問題なく動作しますが、コメント行のコメントを外すと、これは実行されません。どうして?私の理解では、コンパイラは異なる入力パラメータを持っているので、両方のメソッドを区別することができます。なぜ機能的なインターフェイスが必要なのですか?

編集:私は別のメソッドパラメータについて求めているので、リンク重複は私の質問に答えませんでした。しかし、助けてくれた皆さんのおかげで、本当に便利な答えが得られました! :)

EDIT2:申し訳ありませんが、私は明らかにネイティブスピーカーではないんだけど、私自身正確に:

public interface TestInterface { 
    public void hans();     //has no input parameters</br> 
    public void hans(String a);   //has 1 input parameter, type String</br> 
    public void hans(String a, int b); //has 2 input parameters, 1. type = String, 2. type = int</br> 
    public void hans(int a, int b);  //has also 2 input parameters, but not the same and a different order than `hans(String a, int a);`, so you could distinguish both 
} 

public class Test { 

    public static void main(String...args) { 
     TestInterface i =() -> System.out.println("Hans"); 
     i = (String a) -> System.out.println(a); 
     i = (String a, int b) -> System.out.println(a + b); 
     i = (int a, int b) -> System.out.println(a); 

     i.hans(2, 3); //Which method would be called? Of course the one that would take 2 integer arguments. :) 
    } 
} 

私が求めているすべての引数についてです。メソッド名は重要ではありませんが、各メソッドは異なる引数の一意の順序をとります。そのため、Oracleは「Lambda-Interface」ごとに単一のメソッドを作成できるだけでなく、この機能を実装できます。

+3

'int i = 7; i = 5; System.out.println(i); //これが7と5の両方を出力するのであれば、すばらしいとは思いませんか? ' – immibis

+1

あなたの推論は本当に分かりません。何かがインターフェースを実装していない場合、そのタイプはどのようになりますか?あなたが電話をしていないという理由だけで、iPodはiPhoneとしてカウントされません。 – zeroflagL

+0

@immibis:ここで説明する内容は、私が尋ねた内容とは異なります。 :) – codepleb

答えて

20

あなたが書くとき:

TestInterface i =() -> System.out.println("Hans"); 

あなたはTestInterfacevoid hans()方法への実装を与えます。

ラムダ式を複数の抽象メソッド(つまり、非関数型インターフェイス)を持つインターフェイスに割り当てることができる場合、ラムダ式はメソッドの1つのみを実装でき、他のメソッドは実装されません。

異なるシグネチャを持つ2つのラムダ式を同じ変数に割り当てることによって解決することはできません(2つのオブジェクトの参照を1つの変数に割り当てたり、その変数が両方のオブジェクトを一度に参照することはできません) 。

+0

Hmは、論理的に聞こえるが、私はまだオラクルがこのようにした理由について疑問を抱いている。あなたが体を実装したメソッドを単に呼び出すことができれば、どうやらもっと直感的になります。これは、もちろんラムダそのものではなく、インターフェース概念の問題です。ありがとうございました。 :) – codepleb

+2

@TrudleRの場合、Javaは関数型言語になります。あなたがJVM上でそのような実装に興味があるなら。 Scala言語を試すことができます。 –

+0

Hm、Scala Scala Scala。 :D私は本当にこの言語を学ぶ必要があると思う。誰もが最後にそれについて話している。私の場合はその言語で可能ですか?それは本当に美しいだろう。 – codepleb

3

ラムダ機能を作成するために機能インターフェイスを作成する必要はありません。インタフェースを使用すると、将来の関数呼び出し用のインスタンスを作成できます。

あなたのケースでは、既存のインタフェースRunable

Runnable r =() -> System.out.println("Hans");

を使用して、あなたが唯一の短い手としてラムダ->と考えることができ

r.run();

を呼び出すことができます。

Runnable r = new Runnable() { 
    void run() { 
      System.out.println("Hans");` 
    } 
} 

ラムダの場合、上の例のフードの下に作成された匿名クラスは必要ありません。

しかし、これはラムダで使用されるインタフェースは、SAM(シングル抽象メソッド)でなければならないと呼ばれるべきかの方法を理解するためには、いくつかの制限があります。それから、私たちには1つの方法しかありません。より詳細な説明については

を読む:

Introduction to Functional Interfaces – A Concept Recreated in Java 8

13

1つの方法しか含まれていない最も重要な理由は、そうでなければ混乱が起こりやすいということです。インタフェースで複数のメソッドが許可されている場合、引数リストが同じであればどのメソッドでlambdaが選択するべきですか?

interface TestInterface { 
    void first(); 
    void second(); // this is only distinguished from first() by method name 
    String third(); // maybe you could say in this instance "well the return type is different" 
    Object fourth(); // but a String is an Object, too ! 
} 

void test() { 
    // which method are you implementing, first or second ? 
    TestInterface a =() -> System.out.println("Ido mein ado mein"); 
    // which method are you implementing, third or fourth ? 
    TestInterface b =() -> return "Ido mein ado mein"; 
} 
+0

ええ、あなたがそのようなコードを実行したいのであれば、例外が発生するはずです。しかし、私は、異なる議論がコンパイラにとって明らかであるべきだと考えました。同じ名前とパラメータを持つ2つのメソッドを宣言すると、例外も発生するため、Oracleはなぜここでそれを防止する必要がありますか? – codepleb

+0

良い例。ありがとう – greenhorn

3

あなたは匿名クラスを探しているように見えます。次のコードは動作します:

public class Test { 

    public static void main(String...args) { 
     TestInterface i = new TestInterface() { 
      public void hans() { 
       System.out.println("Hans"); 
      } 
      public void hans(String a) { 
       System.out.println(a); 
      } 
     }; 

     i.hans(); 
     i.hans("Hello"); 
    } 
} 

public interface TestInterface { 
    public void hans(); 
    public void hans(String a); 
} 

ラムダ式は、1つの方法だけで匿名クラスを書くための(主に)短い方法です。 (同様に、匿名クラスはあなたが1か所でしか使用しない内部クラスの略語です)

+0

ねえ、私はそれほど初心者ではありません。 :)もちろん私はそれを働かせる方法を知っています。私はちょうど機能的なインターフェイスで動作するようにラムダがカットされている理由を尋ねたがっています。私の場合は、匿名のクラスを作成する(またはクラス自体を実装する)必要があることは明らかです。私が言いたいのは、オラクルがラムダの使用を拡大できたと思うということだけです。しかし、ここでの議論の後、なぜ彼らが機能的なインターフェースを使用するのかは明らかです。しかし、とにかくありがとう。 – codepleb

+0

@TrudleRあなたが考えている方法でlambdaを拡張すると、匿名のクラスと同じになるので、何がポイントになるでしょうか? – immibis

+0

正確な回答ありがとうございます。 – greenhorn

関連する問題