Uma expressão lambda é algo mais que uma classe interna anônima com um único método?


40

Há um novo hype com as tão esperadas expressões lambda no Java 8; a cada três dias, outro artigo aparece com eles sobre como eles são legais.

Até onde eu entendi, uma expressão lambda nada mais é do que uma classe interna anônima com um único método (pelo menos no nível do código de bytes). Além disso, ele vem com outro recurso interessante - a inferência de tipo, mas acredito que o equivalente a isso possa ser alcançado com genéricos em algum nível (é claro que não de maneira organizada, como nas expressões lambda).

Sabendo disso, as expressões lambda trarão algo mais do que apenas uma adição sintática em Java? Posso criar classes mais poderosas e flexíveis ou outras construções orientadas a objetos com expressões lambda que não são possíveis de serem construídas com os recursos de linguagem atuais?


30
Quando um idioma está completo, todo recurso adicional poderia teoricamente ser descrito como "açúcar sintático".
Philipp

34
@ Philipp: Isso está errado. A característica definidora do açúcar sintático é que o desaçúcar é puramente local e não altera a estrutura global do programa. Existem muitos recursos que não podem ser implementados apenas com transformações locais. Por exemplo, se você usar uma linguagem hipotética idêntica a Java, mas com chamadas de cauda apropriadas, não seria possível desugar chamadas de cauda para Java "puro" sem transformar globalmente o programa inteiro.
Jörg W Mittag

2
@ Philipp: Infelizmente, há apenas um voto positivo para comentários, caso contrário, eu recomendaria o comentário de Joerg 1000 vezes. Não, é errado que qualquer recurso possa ser descrito como açúcar sintático. O açúcar sintático não adiciona novas semânticas. De fato, AFAIK, as lambdas Java propostas, NÃO são açúcar sintático para classes internas anônimas especiais, porque elas têm semânticas diferentes.
Giorgio

11
@Giorgio: e que semântica diferente eles têm?
user102008

2
@Giorgio: Sim, mas a conversão de thispara OuterClass.thisfaz parte do processo de descodificação de expressões lambda em classe anônima.
usar o seguinte comando

Respostas:


47

tl; dr: embora seja principalmente açúcar sintático, essa sintaxe mais agradável torna muitas coisas práticas que costumavam terminar em linhas intermináveis ​​e ilegíveis de chaves e parênteses.

Bem, na verdade é o contrário, já que as lambdas são muito mais antigas que o Java. Classes internas anônimas com um único método são (eram) as Java mais próximas das lambdas. É uma aproximação que foi "boa o suficiente" por algum tempo, mas tem uma sintaxe muito desagradável.

Na superfície, as lambdas do Java 8 parecem não ser muito mais que açúcar sintático, mas quando você olha abaixo da superfície, vê toneladas de abstrações interessantes. Por exemplo, a especificação da JVM trata um lambda de maneira bem diferente de um objeto "true" e, embora você possa manipulá- los como se estivessem onde objetos, a JVM não é obrigada a implementá-los como tal.

Porém, embora todo esse truque técnico seja interessante e relevante (uma vez que permite futuras otimizações na JVM!), O benefício real é "apenas" a parte do açúcar sintático.

O que é mais fácil de ler:

myCollection.map(new Mapper<String,String>() {
  public String map(String input) {
    return new StringBuilder(input).reverse().toString();
  }
});

ou:

myCollection.map(element -> new StringBuilder(element).reverse().toString());

ou (usando uma alça de método em vez de uma lambda):

myCollection.map(String::toUpperCase);

O fato de você finalmente poder expressar de forma concisa que anteriormente seria 5 linhas de código (das quais 3 são totalmente chatas) traz uma mudança real do que é prático (mas não do que é possível, concedido).


11
Eu concordo totalmente com a parte de adição de sintaxe; minha pergunta era sobre novas construções orientadas a objetos, possíveis apenas com expressões lambda; afinal Java é uma linguagem orientada a objetos. Pense em comparação com os genéricos e como eles compraram muita flexibilidade em Java, flexibilidade inatingível sem eles.
M3th0dman

7
@ m3th0dman: na verdade, os genéricos não acrescentaram novas habilidades. Um Listpode conter qualquer objeto, um List<String>pode "apenas" segurar seqüências de caracteres. Os genéricos adicionaram uma restrição (e a opção de formalizar restrições!), Não uma adição no poder. Quase tudo desde o Java 1.1 tem sido açúcar sintático. E isso não é necessariamente uma coisa ruim.
Joachim Sauer

3
@ m3th0dman: Na verdade, os genéricos não acrescentaram novas habilidades, porque em Java eles são apenas um açúcar sintático. A List<String>é apenas um Listcom conversão para Stringadicionar alguns valores de retorno. No entanto, eles são extremamente úteis e tornaram a linguagem muito mais conveniente para se escrever. Lambdas são casos semelhantes.
Jan Hudec

3
Na verdade, é muito mais do que apenas açúcar sintático. Grande parte da funcionalidade é implementada como cidadão de primeira classe na JVM por meio do uso do bytecode dinâmico invocado + alguns avanços bastante pesados ​​no sistema de inferência de tipos. Não é implementado como classes internas anônimas.
Martijn Verburg

11
@JanHudec: bem, eles são um pouco mais do que açúcar sintático, porque o compilador realmente os respeita. O tempo de execução não se importa com eles, isso é verdade.
Joachim Sauer

14

Para Java, sim, não passa de uma maneira melhor de criar uma classe interna anônima. Isso ocorre devido à decisão fundamental em java de que todo bit de código de bytes precisa viver dentro de uma classe específica, que não pode ser alterada agora após décadas de código legado a considerar.

No entanto, não é sobre isso que as expressões lambda realmente são. Nos formalismos em que são conceitos nativos, em vez de uma contorção de pular corda, as lambdas são blocos de construção fundamentais; a sintaxe e a atitude das pessoas em relação a elas são muito diferentes. O exemplo de uma função recursiva anônima criada puramente a partir de lambdas em Estrutura e interpretação de programas de computador é capaz de mudar toda a sua concepção de computação. (No entanto, tenho certeza de que a maneira de aprender a programar é esotérica para se tornar uma história de sucesso principal).


11
Aprender que tudo pode ser implementado em termos de lambdas é muito instrutivo e não "esotérico" na minha opinião. (No entanto, acho que a maioria dos "codificadores" não se preocupa com a interessante teoria da CS). Isso não significa que as lambdas sejam especiais; significa apenas que lambdas são um tipo de construção universal. Existem outros, como combinadores SKI. Lambdas são blocos de construção fundamentais em paradigmas funcionais, mas talvez algo mais possa ser fundamental em outro paradigma.
usar o seguinte comando

+1 para "contorção de pular corda": muitas vezes me pergunto por que algumas linguagens continuam mudando para imitar outras linguagens populares e por que os programadores aguentam isso. Eu gosto de lambdas e as uso muito em Scala, Lisp, Haskell, mas em Java ou C ++ elas parecem uma reflexão tardia sobre a linguagem, apenas porque se tornaram populares em outras línguas.
Giorgio

2

Sim, é apenas um açúcar sintático, no sentido de que em qualquer lugar que você escreve um lambda, é possível reescrever essa expressão como uma expressão de classe interna anônima com um método, em que a classe implementa a interface funcional inferida para o contexto do lambda e seria exatamente equivalente semanticamente. E você pode fazer isso simplesmente substituindo a expressão lambda pela expressão de classe anônima, sem alterar nenhuma outra expressão ou linha de código.


11
por que voto negativo? o que eu disse é completamente correta
user102008

O que você escreve parece uma proposta razoável para lambdas Java, mas essa proposta foi descartada em favor de outra ( doanduyhai.wordpress.com/2012/07/12/… ).
Giorgio

11
@Giorgio: Eu não estou "propondo" nada. O que exatamente você não concorda com o que eu disse? Sim, o interior da expressão terá uma aparência diferente, por exemplo, adicionaremos um método e, sim, thisprecisará ser convertido em OuterClass.this. Isso não contradiz o que eu disse - toda expressão lambda pode ser convertida em uma expressão de classe anônima semanticamente equivalente sem alterar nada fora dessa expressão . Eu não disse que o interior não mudaria.
user102008

3
O que você disse está incorreto. A semântica das classes internas lambda e anon não é exatamente a mesma (embora sejam semelhantes). Do alto da minha cabeça, o significado do significado disso muda; e outras classes internas sempre resultam em uma nova instância de um objeto, enquanto um lambda pode ou não.
Stuart Marcas

11
@StuartMarks: Não, você não leu minha resposta. Eu não disse que cada um deles pode fazer tudo o que o outro faz. Eu disse que um lambda tem uma classe anônima equivalente que é semanticamente a mesma. Como eu já disse nos comentários, o thislambda faz parte do açúcar sintático e não faz diferença na semântica. E sobre diferenças na implementação, implementação! = Semântica. Sobre diferenças na identidade do objeto; a identidade do objeto é extremamente tangencial à funcionalidade das lambdas; ninguém verifica a identidade do objeto das classes lambdas / anon de qualquer maneira, porque não é útil.
user102008

1

Joachim Sauer já fez um bom trabalho ao responder sua pergunta, mas apenas sugeriu algo que considero importante. Como as Lambdas não são classes, elas também não são compiladas como tal. Todas as classes internas anônimas resultam na criação de um arquivo .class que, por sua vez, deve ser carregado pelo ClassLoader. Portanto, o uso do Lambdas não apenas torna seu código mais bonito, como também reduz o tamanho do código compilado, o espaço de memória do seu ClassLoader e o tempo necessário para transferir os bits do seu disco rígido.


-1

Não, eles não são.

Outra maneira de dizer isso: as lambdas são uma maneira não-orientada a objetos, por mais concisa que seja, para alcançar a mesma coisa que uma classe anônima ou, minha preferência, classe interna atingiria de maneira orientada a objetos.


11
A programação funcional pode ser totalmente ortogonal à programação orientada a objetos (consulte: Scala e F #). Isso parece a opinião de alguém que simplesmente não gosta de programação funcional por princípio.
KChaloux

11
@KChaloux - Não é um odiador de programação funcional. A resposta é escrita por alguém que prefere ter um martelo E uma chave de fenda em vez de uma chave de fenda. A programação OO é um bom paradigma, assim como a programação funcional. Minha preferência em um idioma é que fique claro sobre suas intenções. Lambdas Sinto-me confuso com a natureza OO do Java. Java não foi projetado para ser uma linguagem funcional. Os seres humanos precisam de estrutura para fazer o seu melhor trabalho.
Guido Anselmi
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.