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


87

それも可能ですか?


6
これがJava 8で可能になったことに注意してください-以下のMark Rotteveelによるラムダ式に関する回答を参照してください。
Josiah Yoder

回答:


81

匿名関数を意味し、Java 8より前のバージョンのJavaを使用している場合、一言で言えば、いいえ。(Java 8+を使用している場合はラムダ式について読んでください

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

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

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


6
未だに。Java 7では、次のことが可能になります
。stackoverflow.com/ questions / 233579 / closures

2
それまでの間、JDK7を待機している間に、匿名メソッドをen.wikipedia.org/wiki/Command_pattern
gpampara

1
closured didntのは、Java 7にそれを作る
するThorbjörnRavnアンデルセン

5
私たちは、Java 8と匿名関数を持っているとして、あなたの答えを変更すべきだと思う
Node.jsの

44

これは匿名の内部クラスの例です。

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[]基づいてを並べ替える方法の例を次に示しますString.length()

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長さの場合など)。

こちらもご覧ください


5
別の発生の大部分はEventListener、平均的なSwingアプリケーションの(サブ)実装として見つけることができます。
BalusC 2010年

@BalusC:「どのように使用されているのか」という質問へのリンクを追加
ポリ

@BalusC:stackoverflowが最近Linkedサイドバーを追加したので、それを利用するために最善を尽くしています。
polygenelubricants

12

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

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

filterメソッドに次のシグネチャがあると仮定します。

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);

詳細については、ラムダ式のチュートリアルをご覧ください。


2
メソッド参照も役立ちます。例えばソート(文字列:: compareToIgnoreCase) docs.oracle.com/javase/tutorial/java/javaOO/...
ジョサイアYoderの

9

既存のタイプのインターフェースを実装または拡張する匿名の内部クラスは、他の回答でも行われていますが、複数のメソッドを実装できることは注目に値します(多くの場合、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と言いますか?


nodefinalここで宣言する必要があります。
BalusC 2010年

@BalusCいいキャッチ。実際、私の間違いは使用することではありませんでしたcur
トム・ホーティン-10

@トム:素晴らしいテクニック+1 実際にどこで使用されていますか?この特定のパターンの名前は?
polygenelubricants

@polygenelubricants私の知る限りではありません。追加のオブジェクト全体がかかります!(そしてクラス。)二重ブレースのイディオムについても、ほとんど同じことが当てはまりました。正しく考えている人は、実行アラウンドイディオムを気にしないようです。
トム・ホーティン-10

@polygenelubricants実際、私は多くの(自己完結型の)再帰アルゴリズムを考えていません。特に、末尾再帰的でない(または簡単にできる)もので、publicメソッドを呼び出すことによって実装できないもの("Node" +2番目のメソッドを必要とするのに少し関係がないことに注意してください)。/私には名前がありません。おそらく、私はネーミング「ポール」(CW)の質問を作成し、忘却に反対投票することができます。
トムホーティン-タックライン

0

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

Javaドキュメントから例を取り、匿名関数、クラスを宣言する方法を知ってみましょう

次の例、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を実装しています。

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.