Wie kann ich eine anonyme Funktion in Java schreiben?

87

Ist es überhaupt möglich?

aarona
quelle
6
Beachten Sie, dass dies jetzt in Java 8 möglich ist - siehe die Antwort zu Lambda Expressions von Mark Rotteveel unten.
Josiah Yoder

Antworten:

81

Wenn Sie eine anonyme Funktion meinen und eine Version von Java vor Java 8 verwenden, dann in einem Wort, nein. ( Lesen Sie mehr über Lambda-Ausdrücke, wenn Sie Java 8+ verwenden. )

Sie können jedoch eine Schnittstelle mit einer Funktion wie der folgenden implementieren:

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

und Sie können dies mit inneren Klassen verwenden, um eine fast anonyme Funktion zu erhalten :)

chris
quelle
6
Noch nicht. In Java 7 wird es möglich sein: stackoverflow.com/questions/233579/closures-in-java-7
Ilya Boyandin
2
Während des Wartens auf JDK7 können anonyme Methoden in einem OO-Kontext unter Verwendung von en.wikipedia.org/wiki/Command_pattern
gpampara
1
Closeded schaffte es nicht nach Java 7.
Thorbjørn Ravn Andersen
5
Ich denke, Sie sollten Ihre Antwort ändern, da wir eine anonyme Funktion mit Java 8 haben.
Node.JS
44

Hier ist ein Beispiel einer anonymen inneren Klasse.

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

Dies ist zwar nicht sehr nützlich, zeigt jedoch, wie eine Instanz einer anonymen inneren Klasse extends Objectund @Overridederen toString()Methode erstellt wird.

Siehe auch


Anonyme innere Klassen sind sehr praktisch, wenn Sie eine implementieren müssen, interfacedie möglicherweise nicht in hohem Maße wiederverwendbar ist (und daher keine Umgestaltung in eine eigene benannte Klasse wert ist). Ein lehrreiches Beispiel ist die Verwendung eines benutzerdefinierten java.util.Comparator<T>Sortiers.

Hier ist ein Beispiel, wie Sie eine String[]basierend auf sortieren können 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]"

Beachten Sie den hier verwendeten Trick zum Vergleichen durch Subtraktion. Es sollte gesagt werden, dass diese Technik im Allgemeinen nicht funktioniert: Sie ist nur anwendbar, wenn Sie garantieren können, dass sie nicht überläuft (dies ist bei StringLängen der Fall ).

Siehe auch

Polygenschmierstoffe
quelle
5
Die meisten anderen Vorkommen können als EventListener(Unter-) Implementierungen in der durchschnittlichen Swing-Anwendung gefunden werden.
BalusC
@ BalusC: Link zur Frage "Wie werden sie verwendet" hinzugefügt
Polygenelubricants
@BalusC: stackoverflow hat kürzlich die LinkedSeitenleiste hinzugefügt , daher gebe ich mein Bestes, um sie zu nutzen.
Polygenelubricants
12

Mit der Einführung des Lambda-Ausdrucks in Java 8 können Sie jetzt anonyme Methoden verwenden.

Angenommen, ich habe eine Klasse Alphaund möchte Alphas nach einer bestimmten Bedingung filtern . Dazu können Sie a verwenden Predicate<Alpha>. Dies ist eine funktionale Schnittstelle mit einer Methode test, die a akzeptiert Alphaund a zurückgibtboolean .

Angenommen, die Filtermethode hat diese Signatur:

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

Mit der alten anonymen Klassenlösung müssten Sie Folgendes tun:

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

Mit den Java 8 Lambdas können Sie Folgendes tun:

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

Weitere Informationen finden Sie im Lambda Expressions-Tutorial

Mark Rotteveel
quelle
2
Methodenreferenzen sind ebenfalls nützlich. zB sort (String :: compareToIgnoreCase) docs.oracle.com/javase/tutorial/java/javaOO/…
Josiah Yoder
9

Anonyme innere Klassen, die die Schnittstelle eines vorhandenen Typs implementieren oder erweitern, wurden in anderen Antworten verwendet, obwohl es erwähnenswert ist, dass mehrere Methoden implementiert werden können (häufig häufig bei Ereignissen im JavaBean-Stil).

Ein wenig erkanntes Merkmal ist, dass anonyme innere Klassen zwar keinen Namen haben, aber einen Typ. Der Schnittstelle können neue Methoden hinzugefügt werden. Diese Methoden können nur in begrenzten Fällen aufgerufen werden. Hauptsächlich direkt auf den newAusdruck selbst und innerhalb der Klasse (einschließlich Instanzinitialisierer). Es mag Anfänger verwirren, aber es kann für die Rekursion "interessant" sein.

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

(Ich habe dies ursprünglich nodeeher mit als curmit der printMethode geschrieben. Sag NEIN zum Erfassen von "implizit final" Einheimischen? )

Tom Hawtin - Tackline
quelle
nodesollte hier deklariert finalwerden.
BalusC
@ BalusC Schöner Fang. Eigentlich war mein Fehler nicht zu benutzen cur.
Tom Hawtin - Tackline
@ Tom: +1 schöne Technik! Wird es tatsächlich irgendwo in der Praxis eingesetzt? Irgendein Name für dieses spezielle Muster?
Polygenschmierstoffe
@polygenelubricants Nicht so weit ich weiß. Kostet ein ganzes zusätzliches Objekt! (Und eine Klasse.) Ähnliches galt für die Doppelklammer-Sprache. Richtig denkende Menschen scheinen die Execute Around-Sprache nicht zu stören.
Tom Hawtin - Tackline
@polygenelubricants Eigentlich scheine ich nicht so viele (in sich geschlossene) rekursive Algorithmen zu haben. Insbesondere solche, die nicht schwanzrekursiv sind (oder leicht zu erstellen sind) und nicht durch Aufrufen der öffentlichen Methode implementiert werden können (beachten Sie, dass es etwas irrelevant ist "Node" +, eine zweite Methode erforderlich zu machen). / Ich habe keinen Namen. Vielleicht könnte ich eine Frage mit dem Namen "Umfrage" (CW) erstellen und sie in Vergessenheit geraten lassen.
Tom Hawtin - Tackline
0

Ja, wenn Sie das neueste Java der Version 8 verwenden. Mit Java8 können anonyme Funktionen definiert werden, die in früheren Versionen nicht möglich waren.

Nehmen wir ein Beispiel aus Java-Dokumenten , um zu erfahren, wie wir anonyme Funktionen und Klassen deklarieren können

Das folgende Beispiel, HelloWorldAnonymousClasses, verwendet anonyme Klassen in den Initialisierungsanweisungen der lokalen Variablen frenchGreeting und spanishGreeting, verwendet jedoch eine lokale Klasse für die Initialisierung der Variablen 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();
    }            
}

Syntax anonymer Klassen

Betrachten Sie die Instanziierung des frenchGreeting-Objekts:

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

Der anonyme Klassenausdruck besteht aus folgenden Elementen:

  • Der newBetreiber
  • Der Name einer zu implementierenden Schnittstelle oder einer zu erweiternden Klasse. In diesem Beispiel implementiert die anonyme Klasse die Schnittstelle HelloWorld.

  • Klammern, die die Argumente für einen Konstruktor enthalten, genau wie ein normaler Ausdruck zur Erstellung von Klasseninstanzen. Hinweis: Wenn Sie eine Schnittstelle implementieren, gibt es keinen Konstruktor. Daher verwenden Sie wie in diesem Beispiel ein leeres Klammerpaar.

  • Ein Body, der ein Klassendeklarationskörper ist. Insbesondere sind im Hauptteil Methodendeklarationen zulässig, Anweisungen jedoch nicht.

mumair
quelle