Java no dia a dia, do jeito certo
Erros comuns em Java que você deve evitar
Se você escreve Java há algum tempo, provavelmente já caiu em alguns desses padrões. A diferença é que, quando você entende o porquê eles são problemáticos, você começa a evitá-los e melhora qualidade, desempenho e manutenção.
1) Tratar null como se fosse regra
Robustez + clareza!
O problema: espalhar checks de
null por todo o código cria caminhos silenciosos,
NullPointerException tardias e contratos pouco claros.
↯
Como evitar: defina invariantes. Se um valor é obrigatório, valide cedo (fail fast). Se é opcional,
modele isso explicitamente (ex.:
Optional em APIs de retorno, ou padrão Null Object quando fizer sentido).
- Evite “if (x != null)” em cascata dentro de métodos longos.
- Prefira validações no início: parâmetros, estado do objeto e pré-condições.
- Trate
nullno limite da aplicação (entrada/integração), não no domínio inteiro.
2) Misturar responsabilidades e criar código difícil de testar
Arquitetura prática!
O problema: classes “Deus” que fazem validação, persistência, transformação e regra de negócio.
O resultado é baixa coesão e alto acoplamento.
✓
Como evitar: separe camadas por responsabilidade e use composição. Garanta que o domínio não dependa
de detalhes de transporte (HTTP), de persistência (SQL/JPA) ou de formatos (JSON).
- Troque “métodos com tudo dentro” por serviços pequenos com contratos claros.
- Padronize transformações (DTO ↔ domínio) para não espalhar mapeamentos em todo lugar.
- Quando testar, prefira testar comportamento (entradas/saídas) e não detalhes internos.
3) Ignorar concorrência (e achar que vai “dar certo”)
Thread-safety + consistência!
O problema: compartilhar estado mutável entre threads sem sincronização adequada. Isso gera
condições de corrida, bugs intermitentes e resultados inconsistentes.
↯
Como evitar: ao invés de “corrigir depois”, deixe o design correr favorável:
imutabilidade, escopo local, coleções thread-safe quando necessário e validações de invariantes.
- Evite instâncias com campos mutáveis usados por múltiplas requests simultâneas.
- Quando precisar de cache, pense em estratégias (ex.: compute-at-once, expiração, locks).
- Entenda o que é atomicidade e o que é apenas visibilidade na JVM.
Exemplo: tornando um parser thread-safe por imutabilidade e evitando estado compartilhado
Boas práticas
// Ruim: estado compartilhado e mutável entre chamadas (potencial condição de corrida)
public class BadParser {
private String buffer = "";
public int parse(String input) {
buffer = input.trim(); // sobrescreve buffer em chamadas concorrentes
return Integer.parseInt(buffer);
}
}
// Bom: sem estado compartilhado (cada chamada usa variáveis locais)
public final class GoodParser {
public int parse(String input) {
String normalized = input == null ? "" : input.trim();
return Integer.parseInt(normalized);
}
}
// Alternativa: validar cedo e falhar com mensagem útil
public final class GoodParserWithValidation {
public int parse(String input) {
if (input == null) throw new IllegalArgumentException("input não pode ser null");
String normalized = input.trim();
if (normalized.isEmpty()) throw new IllegalArgumentException("input vazio");
return Integer.parseInt(normalized);
}
}
✓
Por que isso ajuda: quando você remove estado compartilhado, a chance de bug intermitente cai
drasticamente. E validações claras reduzem erros “tardios”.
4) Abusar de exceptions e engolir erros
Qualidade + diagnóstico!
O problema: capturar
Exception genérico, mascarar a causa raiz ou ignorar o erro.
Isso destrói rastreabilidade e dificulta correção.
↯
Como evitar: capture o necessário, preserve contexto e decida com intenção:
ou você trata, ou você propaga com mensagem e causa.
- Evite
catch (Exception e)sem necessidade. - Não faça “catch” para apenas logar e seguir como se nada tivesse acontecido.
- Use exceções de validação (ex.:
IllegalArgumentException) para pré-condições e exceções específicas para falhas de domínio.
// Exemplo de propagação com causa e contexto (evita “silenciar” falhas)
public class OrderService {
private final PaymentGateway gateway;
public OrderService(PaymentGateway gateway) {
this.gateway = gateway;
}
public void charge(String orderId) {
try {
gateway.charge(orderId);
} catch (PaymentGatewayTimeoutException e) {
// mantém causa e adiciona contexto
throw new RuntimeException("Falha ao cobrar pedido: " + orderId, e);
}
}
}
// Se a exceção é uma falha recuperável, trate; caso contrário, propague com intenção.
Checklist rápido (pra você aplicar hoje)
Revisão✓
Contratos claros: parâmetros obrigatórios validam cedo; opcional não vira surpresa.
✓
Classes coesas: cada componente faz uma coisa; o resto é composição.
↯
Thread-safety: evite estado mutável compartilhado; priorize imutabilidade.
↯
Erros com contexto: não engula exceções; preserve causa e mensagem útil.
Quer continuar melhorando seu Java?
Se esse conteúdo te ajudou, recomendo que você leia outros posts do yurideveloper.com para evoluir arquitetura, qualidade de código e práticas que realmente fazem diferença no dia a dia.