DEV Community

João Victor Martins
João Victor Martins

Posted on

7

[PT-BR] Pattern Matching com instanceof

O Java sempre foi considerado uma linguagem verbosa. Muitas linhas de códigos são escritas para realizar tarefas simples. Apesar de ser uma plataforma de ponta desde os primórdios, esta característica sempre o perseguiu. Na JDK 10 foi incluída uma JEP (JDK Enhancement Proposals), de número 322, que informa uma mudança no lançamento de releases. Novas versões serão lançadas a cada 6 meses. Um dos motivos para tal ação é a melhoria contínua, pois fornece features em menor tempo e recebe-se feedback constante da comunidade. As mudanças são feitas na plataforma em geral, como na JDK, Garbage Collector e na própria linguagem. Falando nas alterações na linguagem, percebe-se uma preocupação com a tal da verbosidade e a JEP 375 é um belo exemplo disso. A JEP em questão é a Pattern Matching for instanceof, que aprimora a linguagem com pattern matching.

Mas afinal, o que é Pattern Matching?

Pattern Matching é uma técnica, que foi adaptada para muitos estilos diferentes de linguagens de programação, desde a década de 1960, incluindo linguagens orientadas a texto como SNOBOL4 e AWK, linguagens funcionais como Haskell e ML, e mais recentemente estendida para linguagens orientadas a objetos como Scala (e mais recentemente, C #).

(https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html)

Pattern Matching permite que a "forma" desejada de um objeto seja expressa de forma concisa (the Patthern) e que várias instruções e expressões testem essa "forma" em relação à entrada (Matching).

(https://openjdk.java.net/jeps/375)

Motivação

Todo desenvolvedor já precisou escrever alguma lógica que verifica se uma expressão tem um determinado tipo e, caso seja verdade, extrair alguma informação para processamento posterior. Um exemplo disso é uma operação com o instanceof.

if(conta instanceof ContaCorrente) {
     ContaCorrente contaCorrente = (ContaCorrente) conta;
     System.out.println(contaCorrente.mostrarExtrato());
} else if(conta instanceof ContaPoupanca) {
     ContaPoupanca contaPoupanca = (ContaPoupanca) conta;
     System.out.println(contaPoupanca.mostrarExtrato());
}
// Demais else if's que poderão existir
Enter fullscreen mode Exit fullscreen mode

O código acima é funcional, porém existem alguns pontos de atenção.

  • Repetição de código: Usa-se ContaCorrente e ContaPoupanca três vezes em duas linhas de código.
  • Casting: Podem esconder erros (bugs) que não serão verificados em tempo de compilação.
  • Baixa coesão: Repetições e castings atrapalham a leitura e consequentemente o entendimento do trecho de código.

Pattern Matching for instanceof

O operador instanceof é estendido para obter um padrão de teste de tipo, em vez de apenas um tipo.

if(conta instanceof ContaCorrente contaCorrente) {
     System.out.println(contaCorrente.mostrarExtrato());
} else if(conta instanceof ContaPoupanca contaPoupanca) {
     System.out.println(contaPoupanca.mostrarExtrato());
}
// Demais else if's que poderão existir
Enter fullscreen mode Exit fullscreen mode

Em relação ao exemplo anterior, o processamento difere em alguns pontos. O operador "combina" o objeto de destino com o padrão de teste de tipo da seguinte maneira. Se conta for uma instância de ContaCorrente, é feito o casting (implícito) para a variável contaCorrente e esta variável estará no escopo do bloco.

É importante ressaltar, que caso exista um else, a variável não fará parte de seu escopo.

if(objeto instanceof String string) {
     // string está no escopo do bloco true
     string.toLowerCase();
} else {
     // string NÃO está no escopo do bloco false
     string.toString();
}
Enter fullscreen mode Exit fullscreen mode

Percebe-se que os pontos de atenção do exemplo anterior já não ocorrem mais.

Futuro

Ainda que haja uma melhora significativa na forma de escrever o código acima, conforme há necessidade de verificar novos tipos de contas, a legibilidade fica comprometida. Pensando nisso, uma futura JEP prevê uma melhora com pattern matchings para switch e o código a seguir será possível

switch(conta) {
     case ContaCorrente cc -> cc.numero = 12345;
     case ContaPoupanca cp -> cp.numero = 12345;
     // Demais cases que poderão existir
}
Enter fullscreen mode Exit fullscreen mode

O mais interessante dessa abordagem é que não é necessário o default, porque deve-se garantir que todas as comparações estão sendo feitas nos cases (Deve-se verificar todos os filhos de Conta) e caso uma ou mais comparações não sejam feitas, haverá um erro de compilação.

Conclusão

Percebe-se que os engenheiros e desenvolvedores da linguagem tem se preocupado com a questão da verbosidade da linguagem. Com o lançamento de releases de 6 em 6 meses, uma melhora rápida pode ser sentida. A ideia do post era mostrar uma dessas melhoras e um plano para o futuro. Se algum dos pontos não ficou claro, estou aberto a dúvidas e/ou sugestões. Até a próxima!

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

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

Okay