Interfaces Funcionais e Lambdas
Interfaces funcionais (SAM Types – Single Abstract Method) são essenciais para expressões lambda. O lambda só existe quando associado a uma interface funcional. Sem essa associação, o código não compila.
Exemplo de Erro:
Object o = () -> {System.out.println("O que sou eu? Que lambda?");};// Erro: Object não é uma interface funcional!Object o = () -> { System.out.println("O que sou eu? Que lambda?"); }; // Erro: Object não é uma interface funcional!Object o = () -> { System.out.println("O que sou eu? Que lambda?"); }; // Erro: Object não é uma interface funcional!
Enter fullscreen mode Exit fullscreen mode
Exemplo Correto com Runnable:
Runnable o = () -> {System.out.println("O que sou eu? Que lambda?");};Runnable o = () -> { System.out.println("O que sou eu? Que lambda?"); };Runnable o = () -> { System.out.println("O que sou eu? Que lambda?"); };
Enter fullscreen mode Exit fullscreen mode
Como os Lambdas São Implementados
O compilador gera classes dinamicamente para representar lambdas, usando MethodHandles e invokedynamic. Essas classes não são visíveis como arquivos .class, mas podem ser identificadas em tempo de execução:
Runnable o = () -> {System.out.println("Classe gerada dinamicamente!");};System.out.println(o.getClass());// Saída: Capitulo3$$Lambda$1@1fc625eRunnable o = () -> { System.out.println("Classe gerada dinamicamente!"); }; System.out.println(o.getClass()); // Saída: Capitulo3$$Lambda$1@1fc625eRunnable o = () -> { System.out.println("Classe gerada dinamicamente!"); }; System.out.println(o.getClass()); // Saída: Capitulo3$$Lambda$1@1fc625e
Enter fullscreen mode Exit fullscreen mode
O nome da classe gerada (ex: Capitulo3$$Lambda$1) depende do contexto e do número de lambdas na classe.
Captura de Variáveis Locais
Lambdas podem acessar variáveis locais do método em que estão definidos, mas elas devem ser efetivamente finais (não modificadas após serem usadas no lambda).
Exemplo 1: Variável Final Explícita
public static void main(String[] args) {final int numero = 5;new Thread(() -> {System.out.println(numero); // Funciona: variável final}).start();}public static void main(String[] args) { final int numero = 5; new Thread(() -> { System.out.println(numero); // Funciona: variável final }).start(); }public static void main(String[] args) { final int numero = 5; new Thread(() -> { System.out.println(numero); // Funciona: variável final }).start(); }
Enter fullscreen mode Exit fullscreen mode
Exemplo 2: Variável Efetivamente Final (não declarada como final)
public static void main(String[] args) {int numero = 5;new Thread(() -> {System.out.println(numero); // Funciona: não é modificada}).start();}public static void main(String[] args) { int numero = 5; new Thread(() -> { System.out.println(numero); // Funciona: não é modificada }).start(); }public static void main(String[] args) { int numero = 5; new Thread(() -> { System.out.println(numero); // Funciona: não é modificada }).start(); }
Enter fullscreen mode Exit fullscreen mode
Exemplo 3: Erro ao Modificar a Variável
public static void main(String[] args) {int numero = 5;new Thread(() -> {System.out.println(numero); // Não compila!}).start();numero = 10; // Variável alterada após ser usada no lambda}public static void main(String[] args) { int numero = 5; new Thread(() -> { System.out.println(numero); // Não compila! }).start(); numero = 10; // Variável alterada após ser usada no lambda }public static void main(String[] args) { int numero = 5; new Thread(() -> { System.out.println(numero); // Não compila! }).start(); numero = 10; // Variável alterada após ser usada no lambda }
Enter fullscreen mode Exit fullscreen mode
Observações Importantes:
Regra da Variável Efetivamente Final:
A partir do Java 8, variáveis locais usadas em lambdas (ou classes anônimas) não precisam ser declaradas como final, mas não podem ser modificadas após serem capturadas.
Concorrência e Estado:
Acesso a objetos mutáveis dentro de lambdas pode causar problemas de concorrência (abordado em capítulos posteriores).
Conclusão:
- Lambdas dependem de interfaces funcionais para existir.
- Classes dinâmicas são geradas em tempo de execução para implementar lambdas.
- Variáveis capturadas devem ser imutáveis (efetivamente finais).
Essas regras garantem segurança e consistência no uso de lambdas, mantendo a legibilidade e a concisão do código.
暂无评论内容