13 dicas e truques da linguagem Java

Web

13 dicas e truques da linguagem Java

Luiz Duarte
Escrito por Luiz Duarte em 29/04/2017
Junte-se a mais de 34 mil devs

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Junta uma dica daqui, outra dali, e voilá, seguem 13 dicas para aumentar sua produtividade enquanto programa usando a linguagem Java. Nada milagroso, mas apenas práticas muitas vezes pouco conhecidas para aumento de produtividade, redução de código e por aí vai. Muitas só funcionam a partir do Java 7 ou 8, mas acredito que nesta altura do campeonato ninguém deveria estar programando em 6 ou frameworks inferiores…

Neste artigo você vai ver:

  1. Operador ternário
  2. ++x, x++, x+= y, etc
  3. Inicializadores de arrays
  4. A diretiva ‘try-with’
  5. Javadocs!
  6. Inicialização double-braces
  7. Instance initializers e static initializers
  8. Diamond notation
  9. Expressões Lambda
  10. Tipo de retorno co-variante
  11. Argumentos variáveis
  12. Use os snippets de código
  13. Generics

Vamos lá!

Curso Node.js e MongoDB

1. Operador Ternário ‘?’

Use-o com moderação ou ele prejudicará a legibilidade de seu código. Basicamente o operador ternário substitui um bloco if tradicional em uma única linha de código. Novidade? NOT! Operadores ternários existem na linguagem C desde a década de 70. Na prática funciona assim, imagine o seguinte bloco de código:

Você pode substituí-lo usando o operador ternário que funciona da seguinte forma (Questão) ? (Ação Positiva) : (Ação Negativa). Vamos ver o exemplo anterior usando operador ternário:

2. ++x, x++, x += y, etc

Quantas vezes você tem de incrementar variáveis? Isso vale também, na maioria dos casos para outros operadores também, que acabam consumindo bastante o nosso tempo programando seus cálculos. Muitas vezes, códigos de mais de uma linha podem facilmente ser reduzidos a poucas instruções em uma única.

Por exemplo, você quer guardar um valor em uma posição de um array e imediatamente incrementar o índice de posições. Um jeito de fazer seria:

Mas este não é o único, nem o melhor jeito de fazer. Primeiro, se você quer acessar a posição do array primeiro e depois incrementá-la, pode fazê-lo da seguinte forma:

Isso por que o incremento unário à direita o faz depois do valor original de indice ter sido lido. O mesmo vale para indice– que decrementaria o valor de índice após sua leitura. Agora, se você quer que ele seja incrementado ANTES da leitura de seu valor:

Assim, o indice já começará em 1 ao invés de 0, o mesmo é válido para –indice, que decrementaria antes de ler o valor.

Mas e se eu quiser aplicar um valor superior a 1, nesse caso os operadores de incremento e decremento unário não me ajudam, certo?

Certo. Para isso temos os auto-operadores, que são aqueles que aplicam uma operação aritmética sobre a própria variável que quer o resultado da operação. Vamos voltar ao primeiro exemplo de código que tivemos neste tópico, apenas mudando o incremento:

Usando os auto-operadores, podemos reescrever este trecho como:

Sendo assim, a variável indice receberá ela mesma acrescida do valor 2. O mesmo vale para -=, *= e /=.

3. Inicializadores de arrays

Cansado de perder várias linhas de código para ficar setando valores em arrays?  A linguagem Java te permite várias formas de construir seu array, a saber:

No primeiro exemplo inicializamos ele com null, para que seja inicializado de fato mais tarde.

Na segunda e terceira linhas, temos inicializações comuns, apenas mudando um pouco a sintaxe, mas ambas possuem efeito idêntico.

Nas duas últimas linhas, temos inicializações já preenchidas com seus respectivos valores iniciais. Note que neste caso eu não precisei dizer quantas posições o meu array irá possuir, ele criará automaticamente com quantas posições forem necessárias para guardar os elementos à direita. Obviamente, eles serão inseridos no array na ordem em que foram descritos.

O último exemplo, em específico, é muito útil e produtivo quando já temos/sabemos os elementos iniciais que nosso array terá.

4. A diretiva ‘try-with’

Uma vez que você precisa alocar um objeto em memória um pouco mais pesado que o normal, como streams e arquivos de mídia, é importante que seja feito um controle mais rigoroso na hora de liberar a memória novamente, evitando problemas futuros. Ou seja, sempre temos de fazer três etapas: criamos o objeto, usamos ele e o descartamos. Isso pode ser ilustrado com o trecho de código abaixo:

A diretiva try, com uso try-with, permite comprimir o código anterior em:

A diretiva try-with somente pode ser utilizada em objetos que implementem a interface java.lang.AutoCloseable.

5. Javadocs!

É comum em projetos Java termos muitas classes e consequentemente muitos métodos, muitos atributos, etc. A existência de cada um destes muitos elementos torna a compreensão de cada um deles complicada com o passar do tempo, principalmente em equipes com vários programadores, sendo que velhos saem e novos entram, mas mesmo quando você programa sozinho, mas não está o tempo todo envolvido com alguns dos projetos que ocasionalmente precisam de manutenção.

Ou seja, depois de um ano ou dois, se você precisar escrever algumas linhas de código ou usar alguma classe complexa que você criou há muito tempo atrás, é uma boa ter comentários nela, certo? Mais do que isso, é bom ter javadocs nela!

Você adiciona Javadocs facilmente em ferramentas como NetBeans usando o snippet (veja mais adiante) /** + ENTER, mas de qualquer forma, você pode fazê-lo manualmente. Por exemplo o Javadoc de um método como esse:

Poderia ser esse (coloque isso logo acima da assinatura do método em questão):

Mas qual a diferença de um Javadoc para um comentário comum? Esse:

Essa janelinha aí aparece sempre que for chamar este método em uma IDE como o NetBeans, lhe dizendo exatamente o que o método faz, os parâmetros, o retorno, etc. E o mesmo pode ser feito para suas classes atributos, etc, lhe ajudando muito com sua produtividade futura!

6. Inicialização double-braces

Sabe a dica 3 sobre inicialização de arrays? Pois é, tenho uma dica parecida para a inicialização de Java Collections: a double-braces initialization. Com ela, você pode instanciar sua Java Collection favorita (como HashSet por exemplo) e  já adicionar os primeiros valores nela, da seguinte forma:

Legal, não?!

7. Instance initializers e Static initializers

Todo mundo conhece os construtores da linguagem Java, certo? Mas e quando temos um algoritmo que deve ser executado em mais de um construtor da mesma classe, como fazemos?

Uma possibilidade é criarmos um método que será chamado dentro dos construtores. Mas apesar de ser uma prática comum, não estaríamos aí repetindo a linha de código de chamada do método, ferindo o princípio DRY? Que tal usar um instance initializer?

Rode esse programa Java acima e você verá que o código “solto” entre chaves é chamado antes do construtor de App passando “one” e novamente antes do construtor de App passando “two’. Sendo assim, é uma inicialização de instância bem útil quando queremos que um algoritmo aconteça em todas as chamadas ao construtor de uma classe.

Mas e se queremos que um código aconteça tão logo uma classe passe a existir no sistema, antes mesmo de seus objetos surgirem? Nesse caso, usamos static initializers, como abaixo:

Nesse caso, basta criar um bloco de inicialização dentro da classe usando a palavra reservada static antes dele. Se você rodar essa aplicação, verá que o bloco static executa antes mesmo da instanciação de App. Mesmo que você nem mesmo instancie App na sua aplicação irá rodar aquele bloco static.

Super interessante!

8. Diamond Notation

Voltando ao assunto de collections, nas versões mais recentes do Java, visando torná-lo um pouco menos verboso quando precisamos ficar instanciando Java Collections foi criada a diamond notation.

O princípio aqui é o seguinte: se o tipo da direita da chamada será o mesmo da esquerda da variável, então não é mais necessário repeti-lo, evitando essa tediosa reescrita que tínhamos antigamente. Imagino a mente do engenheiro criativo que chamou aquele losango formado pelos <> de diamante…

9. Expressões Lambda

Expressões Lambda são expressões de consulta feitas sobre coleções de dados de forma extremamente otimizada e simples, criando um poderosa ferramenta de produtividade. Por exemplo, se tivéssemos uma lista de livros e quiséssemos saber todos os livros que começam com a letra ‘a’?

Tradicionalmente teríamos de fazer um laço para percorrer todos os elementos da lista comparando o título de cada livro e adicionando-os em uma outra fila à medida em que forem encontrados os livros que começam com ‘a’. Com Lambda, tal tarefa se restringe somente a:

Note que este é apenas um dos milhares de uso possíveis de expressões Lambda em Java. Esse poderoso recurso funcional estava demorando pra chegar na linguagem e, se bem compreendido e aplicado, pode mudar drasticamente a sua produtividade enquanto programador Java. Usando uma IDE poderosa como o NetBeans lhe ajuda bastante nesta tarefa pois ela lhe sugere o uso de lambda expressions em diversos momentos que você não se lembraria de usar, sem contar o autocomplete que vai lhe mostrar diversas funcionalidades da mesma, como forEach, removeIf, allMatch, findFirst, etc.

Em todos eles, você terá de trabalhar com o conceito de predicados, que são aquelas expressões anônimas que eu passei por parâmetro no método filter, onde você começa declarando variáveis e depois usa o sinal ‘->’ para dizer que na sequência vem o algoritmo deste método.

Estude a respeito vale a pena. Quem sabe no futuro eu não lance um post focado nisso aqui no blog?

10. Tipo de retorno co-variante

Essa não é uma feature nova, veio no Java 1.5, mas pouca gente conhece, apesar de ser extremamente útil em cenários onde usamos o princípio LSP ou mesmo Generics (mais adiante):

Note que Livro estende Coisa, e que na classe original (Estoque) o método retornarCoisas() traz uma coleção de Coisas, algo bem genérico. Mas na classe filha, Livraria (que nada mais é do que um estoque de livros), sobrescrevemos o método retornarCoisas() para que ele retorne uma coleção de Livro. Muito poderoso!

11. Argumentos variáveis

Essa é bem útil quando você tem um método e ele possui vários parâmetros de mesmo tipo, como se fosse um array, mas você não quer o programador tendo de instanciar um array, popular ele, etc pra poder chamar o método. Sendo assim, a chamada abaixo:

Pode ser substituído por:

O efeito será o mesmo, mas a chamada ficará muito mais simples sem a necessidade de um array por parâmetro. Note que o uso de argumentos variáveis  (as reticências após o tipo do parâmetro) deve ser sempre feito no último parâmetro do método. Note também que se ele for o único parâmetro do método, ele acaba sendo opcional.

12. Use os snippets de código

Snippets são palavras encurtadas que quando usamos no NetBeans (e outras IDEs), seguidas de um TAB, elas se transformam em estruturas de código completas. Experimente digitar os seguintes snippets seguido de TAB na IDE NetBeans:

  • for: monta um laço for padrão;
  • if: monta uma estrutura if padrão;
  • sout: monta um System.out.println();
  • do: cria um bloco do/while;
  • try: cria um bloco try/catch padrão;
  • while: cria um bloco while padrão;
  • psvm: cria um “public void static main…”

13. Generics

Java possui um poderoso recurso de Generics que permite a você associar um tipo de classe à sua classe para que os objetos que ela manipula sejam fortemente tipados ao invés de trabalhar com Object. Um exemplo? ArrayList (lembra do <> do ArrayList? Estamos usando Generics ali), mas podemos usar para criar nossas classes que manipulam outras classes, como Controllers associados a Models no padrão MVC, por exemplo.

Basicamente, quando você cria a sua classe, você diz que ela usará Generics da seguinte forma:

Sendo assim, a classe Estoque se torna genérica para qualquer classe do meu sistema que eu queira “estocar”, porém, diferente de um estoque de Objects, quando eu inicializo o meu estoque eu tenho de dizer qual tipo de objeto estarei estocando, mantendo a tipagem forte.

O método pesquisar do Estoque<Livro> retornará um array de Livro, sendo que T é apenas uma letra arbitrária que será substituída em tempo de compilação pelo tipo especificado.

Assim como Lambda, Generics é muito mais poderoso que isso, mas já deu pra ter um gostinho, certo?!

E aí, tem alguma dica que eu não cobri aqui no post?

* OBS: curtiu o post? Então dá uma olhada no meu livro de Java clicando no banner abaixo pra aprender muito mais!

Livro Java para Iniciantes

TAGS: java

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *