web-dev-qa-db-ja.com

ラムダは機能的なインターフェイスでのみ使用できますか?

これは私がしました:

public class LambdaConflict
{
    public static void main(String args[]){
        //*
        System.out.println(LambdaConflict.get(
            (str) -> "Hello World!! By ME?"
        ));
        /*/
        System.out.println(LambdaConflict.get(new Intf<String> (){
            @Override public String get1(String str){
                return "Hello World!! By get1 " + str;
            }
        }));
        /*****/
    }

    public static String get(Intf<String> i, boolean b){
        return i.get1("from 1");
    }
}

interface Intf<T>
{
    public T get1(T arg1);

    public T get2(T arg1);
}

そして、この例外を取得します:

互換性のないタイプ:Intfは機能的なインターフェースではありません複数の非オーバーライドの抽象メソッドがインターフェースIntfにあります注:一部のメッセージは簡略化されています。 -Xdiags:verboseで再コンパイルして、完全な出力1エラーを取得します。

ラムダを使用して匿名クラスを置き換えることができない条件はありますか?

14
Valen

いいえ。これを「克服」する方法はありません。機能インターフェースには、抽象メソッドが1つだけ必要です。インターフェイスには2つあります。

interface Intf<T> {
    public T get1(T arg1);
    public T get2(T arg1);
}

注:コメントに記載されているように、インターフェースに注釈を付ける必要はありません。ただし、@FunctionalInterfaceアノテーションは、インターフェースが有効な機能インターフェースではない場合にコンパイル時エラーを取得します。したがって、コードのセキュリティが少し向上します。

詳細については、例を参照してください。 http://Java.dzone.com/articles/introduction-functional-1

20
Thomas Uhrig

参考のために、そしてすでに与えられた答えを豊かにするために:

JSR-335:Javaプログラミング言語 のLambda式)のとおり、セクションLambda仕様、パートA:関数型インターフェースでは、

関数型インターフェイスは、(Objectのメソッドを除いて)抽象メソッドを1つだけ持つインターフェイスであり、単一の関数コントラクトを表します。 (場合によっては、この「単一の」メソッドは、スーパーインターフェースから継承されたオーバーライドと同等のシグネチャを持つ複数の抽象メソッドの形を取ることがあります。この場合、継承されたメソッドは論理的に単一のメソッドを表します。)

したがって、必要なのは、メソッドの1つにデフォルトの実装を提供するか、メソッドの1つを別のインターフェースに配置することです。

7
Edwin Dalorzo

それについて考えてください:

  • get1またはget2をオーバーライドするかどうかをコンパイラはどのように知る必要がありますか?

  • get1のみをオーバーライドする場合、get2の実装はどうなりますか?コメントアウトしたコードでも、get2...を実装していないため機能しません。

この制限には理由があります...

3
Idan Arye

@ Thomas-Uhrigが述べたように、機能インターフェースは1つのメソッドしか持つことができません。

これを修正する方法は、主にpublic T get2(T arg1);を使用しないためですが、Intf<T>インターフェースを次のように変更することです:

@FunctionalInterface
interface Intf<T>
{
    public T get1(T arg1);
}
1
DirkyJerky