DEV Community

Cover image for Boas práticas ao usar Lambda e classe anônima em Java
Carolina Dias Fonseca
Carolina Dias Fonseca

Posted on

17 4

Boas práticas ao usar Lambda e classe anônima em Java

Já faz algum tempo que venho falando sobre classes locais, classes anônimas e expressões lambdas. O que são, como usar e quando usar. No atual post vou escrever sobre boas práticas ao usar lambda em Java.

Devo usar tudo o que a linguagem tem?

Acho relevante colocar aqui que apesar do Java ter muitos recursos que podem e realmente ajudam no dia a dia de uma pessoa desenvolvedora, não quer dizer exatamente que esses recursos ajudem a manter um controle e facilidade de leitura/alteração no momento da manutenção do código.

Portanto, quando falamos em “boas práticas” é focado no momento em que a aplicação foi para produção e, dali pra frente, teremos as manutenções, revisões, novas releases e etc. Do meu ponto de vista, sempre temos que pensar que a manutenção não necessariamente será realizada por outra pessoa, mas sim que pode ser qualquer pessoa, incluindo quem criou a aplicação, portanto, é importante pensarmos:

Qual a melhor forma de deixar esse código simples não só para alterações, mas de leitura e entendimento futuro?

Claro que não podemos da performance, segurança, arquitetura e etc, mas sempre mantendo em mente a questão de carga cognitiva de compreensão do código. Afinal, ninguém quer passar uma semana só para tentar entender o que se passa diante dos seus olhos ali na IDE ou então ficar debugando linha a linha para tentar entender o que aquele trecho de código faz ou deixa de fazer.

Vai por mim, já tive que fazer isso porque dei de cara com uma aplicação sem o mínimo de documentação e muito menos com código legível e compreensível. Só para dar uma noção, conseguimos achar um dos responsáveis pela a aplicação e nem ele sabia explicar o que ele e/ou o time tinham feito, então... acho que deu para entender, né?

E como faz?

Pensando nisso, tenho lido muito sobre design pattern (ou, em português, padrões de projeto) tanto da Gang of Four - GoF (ou, em português, Gangue dos Quatro), como o SOLID e, o mais recente nas minhas leituras, o Effective Java (Java Efetivo) do Joshua Bloch.

Esse último, até onde encontrei, está em sua 3ª edição e fala das melhores práticas em Java, usando o Java 9. Questionei no Twitter sobre a relação versão atual do Java (estamos na 18) versus a edição desse livro e a galera mais sênior em relação a mim, super recomendaram a leitura e adicionaram que, para o universo Java, é um dos livros que mais ajudam a entender como otimizar o código, simplificá-lo, além de dar uma visão mais ampla do próprio Java.

Dessa forma, o que Bloch fala sobre Lambdas é, basicamente o seguinte:

Use expressão lambda ao inveś de classe anônima

Agora vamos ao porquê: Classe anônima é mais verbosa, ao passo que a expressão lambda é semelhante a função dentro da classe anônima, porém bem mais concisa.

Veja abaixo:

//Exemplo usando classe anônima
1 Collections.sort(palavras, new Comparator<String>() {
2    public int compare(String palavra1, String palavra2) {
3        return Integer.compare(palavra1.length(), palavra2.length());
4    }
5 });

//Exemplo usando expressão lambda
6 Collections.sort(palavras,
7 (palavra1, palavra2) -> Integer.compare(palavra1.length(), palavra2.length()));
Enter fullscreen mode Exit fullscreen mode

Na expressão lambda e em grande maioria das vezes, o compilador será capaz de deduzir os tipos especificados na linha 2 da classe anônima por um processo chamado por inteferência de tipo, portanto, podemos reduzir ainda mais o exemplo de expressão lambda:

//Exemplo usando classe anônima
1 Collections.sort(palavras, new Comparator<String>() {
2    public int compare(String palavra1, String palavra2) {
3        return Integer.compare(palavra1.length(), palavra2.length());
4    }
5 });

//Exemplo 1 usando expressão lambda
6 Collections.sort(palavras,
7 (palavra1, palavra2) -> Integer.compare(palavra1.length(), palavra2.length()));

//Exemplo 2 usando expressão lambda em sua versão mais concisa
8 palavras.sort(comparingInt(String::length));
Enter fullscreen mode Exit fullscreen mode

Outra dica muito importante que o Bloch passa ainda sobre essa questão de lambdas é de sempre que possível priorizar o uso de métodos genéricos, pois assim diminuirá as chances do compilador dar erro por inferência de tipo.

Por exemplo, as enums facilitam muito o uso interfaces funcionais e lambdas exatamente pelo conceito de métodos mais genéricos.

//Exemplo de uso com Enum sem interface funcional
1 public enum Operacao {
2   SOMA("+") {
3       public double apply(double x, double y) { return x + y; }
4   },
5   SUBTRACAO("-") {
6       public double apply(double x, double y) { return x - y; }
7   },
8   MULTIPLICACAO("*") {
9       public double apply(double x, double y) { return x * y; }
10  },
11  DIVISAO("/") {
12      public double apply(double x, double y) { return x / y; }
13  };

14  private final String simbolo;

//Construtor da enum
15 Operacao(String simbolo) { 
16  this.simbolo = simbolo; 
17 }

//Pelas boas práticas de Bloch, sempre dar o override no toString
18 @Override public String toString() { 
19  return simbolo; 
20 }

//método abstrato para cada implementação
21 public abstract double apply(double x, double y);

22 }
Enter fullscreen mode Exit fullscreen mode

Do jeito que o código está acima, para cada constante será dado um override no método apply afinal, cada operação precisa de uma ação diferente para o mesmo método.

Agora veja como isso fica mais conciso, ou seja, reduzido e simples ao usarmos lambda:

1 public enum Operacao {
2   SOMA("+", (x, y) -> x + y),
3   SUBTRACAO("-", (x, y) -> x - y),
4   MULTIPLICACAO("*", (x, y) -> x * y),
5   DIVISAO("/", (x, y) -> x / y);

6 private final String simbolo;

7 private final DoubleBinaryOperator operacao;

//construtor da enum
8 Operation(String simbolo, DoubleBinaryOperator operacao) {
9       this.simbolo = simbolo;
10      this.operacao = operacao;
11 }

12 @Override public String toString() { 
13  return simbolo; 
14 }

/**o que antes era um método abstrato se torna um método concreto e 
* passamos a utilizar a interface funcional DoubleBinaryOperator cuja a ação é
* receber dois dados e receber um.
*/
15  public double apply(double x, double y) {
16      return operacao.applyAsDouble(x, y);
17  }
18 }
Enter fullscreen mode Exit fullscreen mode

Então vamos esquecer as classes abstrastas e classes anônimas?

Admito que o uso de classe abstrata ainda é algo um pouco confuso para mim se você for pensando em SOLID, por exemplo e até mesmo no próprio Java Efetivo, porém, gosto do ponto que o Bloch trás em seu livro quando diz o seguinte:

“[...] Lambdas are limited to functional interfaces. If you want to create an instance of an abstract class, you can do it with an anonymous class, but not a lambda. Similarly, you can use anonymous classes to create instances of interfaces with multiple abstract methods.”

Que, em tradução livre, nas mais é do que o uso de lambdas se restrigem ao uso de interfaces funcionais (algo que a própria documentação do Java reforça) e diz que a classe abstrata você utiliza numa classe anônima e NÃO em um lambda. Da mesma forma que você utiliza a classe anônima para criar instâncias de interfaces com múltiplos métodos.

Fontes: Documentação Java

Effective Java - Joshua Bloch

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (1)

Collapse
 
luccabiagi profile image
Lucca Biagi de Paula Prado

Gostei muito do "Devo usar tudo o que a linguagem tem?"
Pois me lembrou a discussão do uso do EVAL do JS.

No geral, artigo muito bom! Parabéns!

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay