Comment puis-je écrire une fonction anonyme en Java?

87

Est-ce même possible?

Aarona
la source
6
Notez que cela est désormais possible dans Java 8 - voir la réponse sur les expressions Lambda par Mark Rotteveel ci-dessous.
Josiah Yoder

Réponses:

81

si vous parlez d'une fonction anonyme et que vous utilisez une version de Java antérieure à Java 8, alors en un mot, non. ( En savoir plus sur les expressions lambda si vous utilisez Java 8+ )

Cependant, vous pouvez implémenter une interface avec une fonction comme celle-ci:

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

et vous pouvez l'utiliser avec des classes internes pour obtenir une fonction presque anonyme :)

Chris
la source
6
Pas encore. Dans Java 7, cela va être possible: stackoverflow.com/questions/233579/closures-in-java-7
Ilya Boyandin
2
En attendant, en attendant JDK7, les méthodes anonymes peuvent être émulées dans un contexte OO en utilisant en.wikipedia.org/wiki/Command_pattern
gpampara
1
fermé n'a pas réussi à atteindre Java 7.
Thorbjørn Ravn Andersen
5
Je pense que vous devriez modifier votre réponse car nous avons une fonction anonyme avec Java 8.
Node.JS
44

Voici un exemple de classe interne anonyme.

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

Ce n'est pas très utile en l'état, mais cela montre comment créer une instance d'une classe interne anonyme extends Objectet @Overridesa toString()méthode.

Voir également


Les classes internes anonymes sont très pratiques lorsque vous avez besoin d'implémenter une interfaceclasse qui n'est peut-être pas hautement réutilisable (et ne vaut donc pas la peine d'être refactorisée en sa propre classe nommée). Un exemple instructif est l'utilisation d'une coutume java.util.Comparator<T>pour le tri.

Voici un exemple de la façon dont vous pouvez trier un en String[]fonction de 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]"

Notez l'astuce de comparaison par soustraction utilisée ici. Il faut dire que cette technique est en général cassée: elle n'est applicable que lorsque l'on peut garantir qu'elle ne débordera pas (c'est le cas des Stringlongueurs).

Voir également

lubrifiants polygènes
la source
5
La majorité des autres occurrences peuvent être trouvées en tant que EventListener(sous) implémentations dans l'application Swing moyenne.
BalusC
@BalusC: ajout d'un lien vers la question "comment sont-ils utilisés"
polygenelubricants
@BalusC: stackoverflow a récemment ajouté la Linkedbarre latérale, donc je fais de mon mieux pour l'utiliser.
polygenelubricants
12

Avec l'introduction de l'expression lambda dans Java 8, vous pouvez désormais avoir des méthodes anonymes.

Disons que j'ai une classe Alphaet que je veux filtrer les Alphas sur une condition spécifique. Pour ce faire, vous pouvez utiliser un fichier Predicate<Alpha>. Il s'agit d'une interface fonctionnelle qui a une méthode testqui accepte un Alphaet retourne un boolean.

En supposant que la méthode de filtrage a cette signature:

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

Avec l'ancienne solution de classe anonyme, vous auriez besoin de quelque chose comme:

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

Avec les lambdas Java 8, vous pouvez faire:

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

Pour plus d'informations, consultez le didacticiel sur les expressions Lambda

Mark Rotteveel
la source
2
Les références de méthode sont également utiles. par exemple sort (String :: compareToIgnoreCase) docs.oracle.com/javase/tutorial/java/javaOO/…
Josiah Yoder
9

Des classes internes anonymes implémentant ou étendant l'interface d'un type existant ont été faites dans d'autres réponses, bien qu'il soit intéressant de noter que plusieurs méthodes peuvent être implémentées (souvent avec des événements de style JavaBean, par exemple).

Une caractéristique peu reconnue est que bien que les classes internes anonymes n'aient pas de nom, elles ont un type. De nouvelles méthodes peuvent être ajoutées à l'interface. Ces méthodes ne peuvent être invoquées que dans des cas limités. Principalement directement sur l' newexpression elle-même et au sein de la classe (y compris les initialiseurs d'instance). Cela peut dérouter les débutants, mais cela peut être "intéressant" pour la récursivité.

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

(J'ai initialement écrit ceci en utilisant nodeplutôt que curdans la printméthode. Dites NON à la capture "implicitement final" des locaux? )

Tom Hawtin - Tacle
la source
nodedoit être déclaré finalici.
BalusC
@BalusC Belle prise. En fait, mon erreur a été de ne pas utiliser cur.
Tom Hawtin - tackline
@Tom: +1 belle technique! Est-il réellement utilisé n'importe où dans la pratique? Un nom pour ce modèle spécifique?
polygenelubricants
@polygenelubricants Pas pour autant que je sache. Coûte un objet supplémentaire! (Et une classe.) Il en était de même pour l'idiome à double accolade. Les gens bien pensants ne semblent pas se soucier de l'idiome Execute Around.
Tom Hawtin - tackline
@polygenelubricants En fait, je ne semble pas avoir autant d'algorithmes récursifs (autonomes). En particulier ceux qui ne sont pas récursifs à la queue (ou qui ne peuvent être facilement mis en œuvre) et qui ne peuvent pas être implémentés en appelant la méthode publique (notez le peu non pertinent "Node" +pour rendre une deuxième méthode nécessaire). / Je n'ai pas de nom. Peut-être pourrais-je créer une question de dénomination «sondage» (CW), et la faire rejeter dans l'oubli.
Tom Hawtin - tackline
0

Oui si vous utilisez le dernier java qui est la version 8. Java8 permet de définir des fonctions anonymes, ce qui était impossible dans les versions précédentes.

Prenons l'exemple de la documentation java pour savoir comment déclarer des fonctions et des classes anonymes

L'exemple suivant, HelloWorldAnonymousClasses, utilise des classes anonymes dans les instructions d'initialisation des variables locales frenchGreeting et spanishGreeting, mais utilise une classe locale pour l'initialisation de la variable 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();
    }            
}

Syntaxe des classes anonymes

Considérez l'instanciation de l'objet 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);
        }
    };

L'expression de classe anonyme comprend les éléments suivants:

  • L' newopérateur
  • Le nom d'une interface à implémenter ou d'une classe à étendre. Dans cet exemple, la classe anonyme implémente l'interface HelloWorld.

  • Parenthèses contenant les arguments d'un constructeur, tout comme une expression de création d'instance de classe normale. Remarque: Lorsque vous implémentez une interface, il n'y a pas de constructeur, vous utilisez donc une paire vide de parenthèses, comme dans cet exemple.

  • Un corps, qui est un corps de déclaration de classe. Plus précisément, dans le corps, les déclarations de méthode sont autorisées mais les instructions ne le sont pas.

mumair
la source