Como posso escrever uma função anônima em Java?

87

É mesmo possível?

Aarona
fonte
6
Observe que agora isso é possível em Java 8 - consulte a resposta sobre Lambda Expressions de Mark Rotteveel abaixo.
Josiah Yoder

Respostas:

81

se você quer dizer uma função anônima e está usando uma versão do Java anterior ao Java 8, em uma palavra, não. ( Leia sobre as expressões lambda se você usar Java 8+ )

No entanto, você pode implementar uma interface com uma função como esta:

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

e você pode usar isso com classes internas para obter uma função quase anônima :)

Chris
fonte
6
Ainda não. Em Java 7, isso será possível: stackoverflow.com/questions/233579/closures-in-java-7
Ilya Boyandin
2
Enquanto isso, enquanto espera pelo JDK7, os métodos anônimos podem ser emulados em um contexto OO usando en.wikipedia.org/wiki/Command_pattern
gpampara
1
fechado não chegou ao Java 7.
Thorbjørn Ravn Andersen
5
Acho que você deve modificar sua resposta, pois temos função anônima com Java 8.
Node.JS
44

Aqui está um exemplo de uma classe interna anônima.

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

Isso não é muito útil como é, mas mostra como criar uma instância de uma classe interna anônima que extends Objecte @OverrideseustoString() método.

Veja também


Classes internas anônimas são muito úteis quando você precisa implementar um interfaceque pode não ser altamente reutilizável (e, portanto, não vale a pena refatorar para sua própria classe nomeada). Um exemplo instrutivo é usar um modelojava.util.Comparator<T> para classificação.

Aqui está um exemplo de como você pode classificar com String[]base em 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]"

Observe o truque de comparação por subtração usado aqui. Deve ser dito que esta técnica é quebrada em geral: ela só é aplicável quando você pode garantir que não irá estourar (como é o caso comString comprimentos).

Veja também

poligenelubrificantes
fonte
5
A maioria das outras ocorrências podem ser encontradas como EventListener(sub) implementações no aplicativo Swing médio.
BalusC de
@BalusC: adicionado link para a questão "como são usados"
poligenelubrificantes
@BalusC: stackoverflow adicionou recentemente a Linkedbarra lateral, então estou fazendo o meu melhor para fazer uso dela.
poligenelubrificantes
12

Com a introdução da expressão lambda no Java 8, agora você pode ter métodos anônimos.

Digamos que eu tenha uma aula Alphae desejo filtrar Alphas em uma condição específica. Para fazer isso, você pode usar um Predicate<Alpha>. Esta é uma interface funcional que possui um método testque aceita um Alphae retorna um boolean.

Supondo que o método de filtro tenha esta assinatura:

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

Com a antiga solução de classe anônima, você precisaria de algo como:

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

Com os lambdas do Java 8 você pode fazer:

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

Para obter informações mais detalhadas, consulte o tutorial de Expressões Lambda

Mark Rotteveel
fonte
2
Referências de métodos também são úteis. por exemplo, sort (String :: compareToIgnoreCase) docs.oracle.com/javase/tutorial/java/javaOO/…
Josiah Yoder
9

Classes internas anônimas que implementam ou estendem a interface de um tipo existente foram feitas em outras respostas, embora seja importante notar que vários métodos podem ser implementados (geralmente com eventos no estilo JavaBean, por exemplo).

Um recurso pouco conhecido é que, embora as classes internas anônimas não tenham um nome, elas têm um tipo. Novos métodos podem ser adicionados à interface. Esses métodos só podem ser chamados em casos limitados. Principalmente diretamente na newprópria expressão e dentro da classe (incluindo inicializadores de instância). Isso pode confundir os iniciantes, mas pode ser "interessante" para a recursão.

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

(Escrevi originalmente usando, em nodevez de curno printmétodo. Diga NÃO à captura de finallocais " implicitamente "? )

Tom Hawtin - tackline
fonte
nodedeve ser declarado finalaqui.
BalusC
@BalusC Boa captura. Na verdade, meu erro foi não usar cur.
Tom Hawtin - tackline
@Tom: +1 técnica legal! É realmente usado em qualquer lugar na prática? Qualquer nome para este padrão específico?
poligenelubrificantes de
@polygenelubricants Não que eu saiba. Custa todo um objeto extra! (E uma aula.) Praticamente o mesmo acontecia com o idioma de chave dupla. Pessoas que pensam corretamente não parecem se importar com o idioma Execute Around.
Tom Hawtin - tackline
@polygenelubricants Na verdade, não parece que muitos algoritmos recursivos (independentes). Particularmente aqueles que não são recursivos na cauda (ou facilmente tornados) e não podem ser implementados chamando o método público (observe o pouco irrelevante "Node" +para tornar um segundo método necessário). / Eu não tenho nome. Talvez eu pudesse criar uma pergunta de "enquete" (CW) de nomenclatura e recebê-la no esquecimento.
Tom Hawtin - tackline
0

Sim, se você estiver usando o java mais recente, que é a versão 8. Java8 torna possível definir funções anônimas que eram impossíveis nas versões anteriores.

Vamos dar exemplos de documentos java para saber como podemos declarar funções anônimas, classes

O exemplo a seguir, HelloWorldAnonymousClasses, usa classes anônimas nas instruções de inicialização das variáveis ​​locais frenchGreeting e spanishGreeting, mas usa uma classe local para a inicialização da variável 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();
    }            
}

Sintaxe de classes anônimas

Considere a instanciação do 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);
        }
    };

A expressão de classe anônima consiste no seguinte:

  • A newoperadora
  • O nome de uma interface a ser implementada ou uma classe a ser estendida. Neste exemplo, a classe anônima está implementando a interface HelloWorld.

  • Parênteses que contêm os argumentos para um construtor, assim como uma expressão normal de criação de instância de classe. Nota: Quando você implementa uma interface, não há construtor, então você usa um par vazio de parênteses, como neste exemplo.

  • Um corpo, que é um corpo de declaração de classe. Mais especificamente, no corpo, as declarações de método são permitidas, mas as instruções não.

mumair
fonte