¿Cómo puedo escribir una función anónima en Java?


87

¿Es siquiera posible?


6
Tenga en cuenta que esto ahora es posible en Java 8; consulte la respuesta sobre Expresiones Lambda de Mark Rotteveel a continuación.
Josiah Yoder

Respuestas:


81

si te refieres a una función anónima y estás usando una versión de Java anterior a Java 8, entonces en una palabra, no. ( Lea acerca de las expresiones lambda si usa Java 8+ )

Sin embargo, puede implementar una interfaz con una función como esta:

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

y puede usar esto con clases internas para obtener una función casi anónima :)



2
Mientras tanto, mientras espera JDK7, los métodos anónimos se pueden emular en un contexto OO usando en.wikipedia.org/wiki/Command_pattern
gpampara

1
closured no llegó a Java 7.
Thorbjørn Ravn Andersen

5
Creo que debería modificar su respuesta ya que tenemos una función anónima con Java 8.
Node.JS

45

Aquí hay un ejemplo de una clase interna anónima.

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

Esto no es muy útil tal como está, pero muestra cómo crear una instancia de una clase interna anónima extends Objecty @Overridesu toString()método.

Ver también


Las clases internas anónimas son muy útiles cuando necesita implementar una interfaceque puede no ser altamente reutilizable (y por lo tanto no vale la pena refactorizarla a su propia clase nombrada). Un ejemplo instructivo es el uso de una costumbre java.util.Comparator<T>para ordenar.

Aquí tienes un ejemplo de cómo puedes ordenar un String[]archivo 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]"

Tenga en cuenta el truco de comparación por resta que se utiliza aquí. Hay que decir que esta técnica está rota en general: solo es aplicable cuando se puede garantizar que no se desbordará (tal es el caso de las Stringlongitudes).

Ver también


5
La mayoría de otras ocurrencias se pueden encontrar como EventListener(sub) implementaciones en la aplicación Swing promedio.
BalusC

@BalusC: se agregó un enlace a la pregunta "cómo se usan"
polygenelubricants

@BalusC: stackoverflow agregó recientemente la Linkedbarra lateral, así que estoy haciendo todo lo posible para usarla.
polygenelubricants

12

Con la introducción de la expresión lambda en Java 8, ahora puede tener métodos anónimos.

Digamos que tengo una clase Alphay quiero filtrar Alphamensajes en una condición específica. Para hacer esto, puede usar un Predicate<Alpha>. Esta es una interfaz funcional que tiene un método testque acepta un Alphay devuelve un boolean.

Suponiendo que el método de filtro tiene esta firma:

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

Con la antigua solución de clase anónima, necesitaría algo como:

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

Con las lambdas de Java 8 puedes hacer:

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

Para obtener información más detallada, consulte el tutorial de expresiones Lambda


2
Las referencias de métodos también son útiles. por ejemplo, sort (String :: compareToIgnoreCase) docs.oracle.com/javase/tutorial/java/javaOO/…
Josiah Yoder

9

Las clases internas anónimas que implementan o extienden la interfaz de un tipo existente se han realizado en otras respuestas, aunque vale la pena señalar que se pueden implementar múltiples métodos (a menudo con eventos de estilo JavaBean, por ejemplo).

Una característica poco reconocida es que aunque las clases internas anónimas no tienen un nombre, sí tienen un tipo. Se pueden agregar nuevos métodos a la interfaz. Estos métodos solo se pueden invocar en casos limitados. Principalmente directamente en la newexpresión en sí y dentro de la clase (incluidos los inicializadores de instancia). Puede confundir a los principiantes, pero puede ser "interesante" para la recursividad.

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

(Originalmente escribí esto usando en nodelugar de curen el printmétodo. ¿ Di NO a capturar finallocales "implícitamente "? )


nodedebe declararse finalaquí.
BalusC

@BalusC Buena captura. En realidad, mi error fue no usar cur.
Tom Hawtin - tackline

@Tom: ¡+1 buena técnica! ¿Se usa realmente en alguna parte en la práctica? ¿Algún nombre para este patrón específico?
polygenelubricants

@polygenelubricants No que yo sepa. ¡Cuesta todo un objeto extra! (Y una clase.) Lo mismo sucedió con el modismo de doble corchete. A las personas que piensan correctamente no parece importarles el modismo Execute Around.
Tom Hawtin - tackline

@polygenelubricants En realidad, no me parece que haya muchos algoritmos recursivos (autónomos). Particularmente aquellos que no son recursivos de cola (o fáciles de hacer) y no se pueden implementar llamando al método público (tenga en cuenta lo ligeramente irrelevante "Node" +para hacer necesario un segundo método). / No tengo nombre. Quizás podría crear una pregunta de "encuesta" de nombres (CW), y hacer que se rechace en el olvido.
Tom Hawtin - tackline

1

Sí, si está utilizando la última versión de Java, que es la versión 8. Java8 permite definir funciones anónimas que era imposible en versiones anteriores.

Tomemos un ejemplo de los documentos de Java para saber cómo podemos declarar funciones anónimas, clases

El siguiente ejemplo, HelloWorldAnonymousClasses, usa clases anónimas en las declaraciones de inicialización de las variables locales frenchGreeting y spanishGreeting, pero usa una clase local para la inicialización 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();
    }            
}

Sintaxis de clases anónimas

Considere la instanciación del objeto 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);
        }
    };

La expresión de clase anónima consta de lo siguiente:

  • El newoperador
  • El nombre de una interfaz para implementar o una clase para extender. En este ejemplo, la clase anónima está implementando la interfaz HelloWorld.

  • Paréntesis que contienen los argumentos de un constructor, como una expresión de creación de instancia de clase normal. Nota: cuando implementa una interfaz, no hay un constructor, por lo que usa un par de paréntesis vacíos, como en este ejemplo.

  • Un cuerpo, que es un cuerpo de declaración de clase. Más específicamente, en el cuerpo, las declaraciones de métodos están permitidas pero las declaraciones no.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.