Principais erros de desenvolvedores Java iniciantes: nível avançado
Muitos desenvolvedores, após dominarem os fundamentos do Java, passam a escrever código mais complexo, mas continuam cometendo erros típicos que reduzem o desempenho e a confiabilidade das aplicações. Neste artigo, analisaremos os principais erros em nível avançado que ocorrem com desenvolvedores Java e mostraremos como evitá-los. O artigo será útil para aqueles que já conhecem a sintaxe da linguagem, mas desejam aprofundar seus conhecimentos.
1. Uso incorreto de Optional
A classe Optional foi introduzida no Java 8 para lidar com NullPointerException. No entanto, muitos desenvolvedores a utilizam incorretamente, transformando uma solução elegante em uma fonte de novos problemas.
Erro: Uso de Optional.get() sem verificação
Um dos erros mais comuns é chamar o método get() sem antes verificar isPresent(). Isso resulta na exceção NoSuchElementException.
// IncorretoOptional<String> name = Optional.ofNullable(getName());String result = name.get(); // Exceção se name == null
// CorretoString result = name.orElse("Default");// Ou com tratamentoname.ifPresent(System.out::println);Erro: Uso de Optional em campos de classe
Optional não foi projetado para ser usado como campo de classe ou parâmetro de método. Isso quebra a serialização e adiciona complexidade desnecessária.
// Incorretopublic class User { private Optional<String> email; // Não serializável}
// Corretopublic class User { private String email; // null significa ausência}Erro: Encadeamento de Optional.orElse() com cálculos caros
O método orElse() sempre avalia o argumento, mesmo que o valor esteja presente. Use orElseGet() para cálculos preguiçosos.
// Incorreto — expensiveCall() é executado sempreString result = optional.orElse(expensiveCall());
// Correto — expensiveCall() é executado apenas quando o valor está ausenteString result = optional.orElseGet(() -> expensiveCall());2. Vazamentos de memória e trabalho incorreto com coleções
Desenvolvedores avançados frequentemente enfrentam vazamentos de memória difíceis de detectar. Vamos analisar as principais causas.
Erro: Esquecer de sobrescrever equals() e hashCode()
Ao usar objetos em HashMap ou HashSet sem equals() e hashCode() corretos, os objetos não são removidos da coleção, causando vazamentos.
public class Key { private int id; // Esqueceu de sobrescrever equals() e hashCode() // Agora as chaves são consideradas diferentes, mesmo que o id seja igual}
Map<Key, String> map = new HashMap<>();map.put(new Key(1), "value");map.get(new Key(1)); // null — vazamento de memóriaErro: Armazenar objetos grandes em coleções static
Coleções estáticas vivem até o fim da aplicação. Se dados forem adicionados sem controle, isso levará a OutOfMemoryError.
// Má práticapublic class CacheManager { private static List<byte[]> cache = new ArrayList<>(); public static void addData(byte[] data) { cache.add(data); // Cresce infinitamente }}
// Solução: use WeakHashMap ou limite o tamanhoprivate static Map<String, byte[]> cache = new WeakHashMap<>();Erro: Fechar recursos através de finalize()
O método finalize() está obsoleto e não é confiável. Use try-with-resources para fechamento automático.
// Incorretopublic class Resource { @Override protected void finalize() throws Throwable { // Fechamento do recurso — pode não ser chamado