web-dev-qa-db-ja.com

Javaで匿名関数を作成するにはどうすればよいですか?

それも可能ですか?

85
aarona

匿名関数を意味し、Javaの前にJavaのバージョンを使用している場合、8then言葉、いや。 ( Java 8+を使用する場合のラムダ式について読む

ただし、次のような関数を使用してインターフェイスを実装できます。

Comparator<String> c = new Comparator<String>() {
    int compare(String s, String s2) { ... }
};

これを内部クラスで使用して、ほぼ匿名の関数を取得できます:)

77
chris

匿名の内部クラスの例を次に示します。

System.out.println(new Object() {
    @Override public String toString() {
        return "Hello world!";
    }
}); // prints "Hello world!"

これはあまり有用ではありませんが、extends Objectおよび@OverrideがそのtoString()メソッドである匿名内部クラスのインスタンスを作成する方法を示しています。

こちらもご覧ください


匿名の内部クラスは、高度に再利用できない(したがって、独自の名前付きクラスにリファクタリングする価値がない)interfaceを実装する必要がある場合に非常に便利です。有益な例は、カスタムの Java.util.Comparator<T> を使用してソートすることです。

String.length()に基づいてString[]をソートする方法の例を次に示します。

import Java.util.*;
//...

String[] arr = { "xxx", "cd", "ab", "z" };
Arrays.sort(arr, new Comparator<String>() {
    @Override public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }           
});
System.out.println(Arrays.toString(arr));
// prints "[z, cd, ab, xxx]"

ここで使用される減算による比較のトリックに注意してください。一般に、この手法は壊れていると言わなければなりません。オーバーフローしないことを保証できる場合にのみ適用されます(Stringの長さの場合)。

こちらもご覧ください

44

Java 8のラムダ式の導入により、匿名メソッドを使用できるようになりました。

クラスAlphaがあり、特定の条件でAlphasをフィルタリングするとします。これを行うには、 Predicate<Alpha> を使用できます。これは、testを受け入れ、Alphaを返すメソッドbooleanを備えた機能インターフェイスです。

フィルターメソッドに次のシグネチャがあると仮定します。

List<Alpha> filter(Predicate<Alpha> filterPredicate)

古い匿名クラスソリューションでは、次のようなことが必要になります。

filter(new Predicate<Alpha>() {
   boolean test(Alpha alpha) {
      return alpha.centauri > 1;
   }
});

Java 8ラムダを使用すると、次のことができます。

filter(alpha -> alpha.centauri > 1);

詳細については、 Lambda Expressions tutorial をご覧ください。

11
Mark Rotteveel

既存の型のインターフェースを実装または拡張する匿名の内部クラスは、他の回答で行われましたが、複数のメソッドを実装できることは注目に値します(多くの場合、たとえばJavaBeanスタイルのイベントを使用)。

少し認識されている機能は、匿名の内部クラスには名前がありませんが、タイプがあることです。インターフェイスに新しいメソッドを追加できます。これらのメソッドは、限られた場合にのみ呼び出すことができます。主にnew式自体およびクラス内(インスタンス初期化子を含む)で直接。初心者を混乱させるかもしれませんが、再帰にとっては「興味深い」ことがあります。

private static String pretty(Node node) {
    return "Node: " + new Object() {
        String print(Node cur) {
            return cur.isTerminal() ?
                cur.name() :
                ("("+print(cur.left())+":"+print(cur.right())+")");
        }
    }.print(node);
}

(元々、これはnodeメソッドではなくcurではなくprintを使用して作成しました。「暗黙的にfinal」ローカルをキャプチャすることにNOと言いますか?

はい。最新のJava(バージョン8)を使用している場合、Java8では、以前のバージョンでは不可能だった匿名関数を定義できます。

Java docs の例を使用して、匿名関数、クラスを宣言する方法を理解しましょう

次の例のHelloWorldAnonymousClassesは、ローカル変数frenchGreetingおよびspanishGreetingの初期化ステートメントで匿名クラスを使用しますが、変数englishGreetingの初期化にはローカルクラスを使用します。

public class HelloWorldAnonymousClasses {

    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }

    public void sayHello() {

        class EnglishGreeting implements HelloWorld {
            String name = "world";
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }

        HelloWorld englishGreeting = new EnglishGreeting();

        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };

        HelloWorld spanishGreeting = new HelloWorld() {
            String name = "mundo";
            public void greet() {
                greetSomeone("mundo");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };
        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp =
            new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }            
}

匿名クラスの構文

FrenchGreetingオブジェクトのインスタンス化を検討してください。

    HelloWorld frenchGreeting = new HelloWorld() {
        String name = "tout le monde";
        public void greet() {
            greetSomeone("tout le monde");
        }
        public void greetSomeone(String someone) {
            name = someone;
            System.out.println("Salut " + name);
        }
    };

匿名クラス式は次で構成されます。

  • new演算子
  • 実装するインターフェースまたは拡張するクラスの名前。この例では、匿名クラスはインターフェイスHelloWorldを実装しています。

  • 通常のクラスインスタンス作成式と同様に、コンストラクターへの引数を含む括弧。注:インターフェースを実装する場合、コンストラクターがないため、この例のように、空の括弧のペアを使用します。

  • 本体。クラス宣言の本体です。より具体的には、本文では、メソッド宣言は許可されていますが、ステートメントは許可されていません。

0
mumair