
Se você ainda está digitando getters, setters, equals() e hashCode() manualmente, ou se seus Data Transfer Objects (DTOs) parecem ter sido escritos em 2012, você está perdendo o segredo.
Você está escrevendo Java demais.
Já trabalhei em equipes que passaram semanas debatendo Lombok versus frameworks de imutabilidade, só para introduzir problemas complexos de build e bugs ocultos. A Java Virtual Machine (JVM) moderna — especificamente Java 17 LTS e versões posteriores — já resolveu esses problemas nativamente.
Isso não é apenas “açúcar sintático”. Esses recursos reduzem fundamentalmente o código repetitivo (boilerplate), melhoram a legibilidade do código e, mais importante, permitem otimizações mais profundas do compilador que reduzem a carga cognitiva.
Este é o verdadeiro “código secreto” para construir microsserviços mais rápidos, sustentáveis e baratos.
Aqui estão os 10 recursos que os desenvolvedores sêniores utilizam para reduzir sua base de código Java pela metade.
record: O Exterminador de BoilerplateEsta é a maior conquista para classes centradas em dados. Se o propósito principal de uma classe é armazenar dados, use um record. Eles são imutáveis e geram automaticamente construtores, getters, equals(), hashCode() e toString().
A matemática é simples: 10 linhas de configuração se tornam uma.
// User.java (aproximadamente 25 linhas de boilerplate + 2 campos)
public final class User {
private final long id;
private final String username;
public User(long id, String username) {
this.id = id;
this.username = username;
}
// Mais 15 linhas de getters, equals, hashcode e toString...
}// User.java (1 linha)
public record User(long id, String username) { }
// Uso:
var user = new User(42, "theIndieDev");
long userId = user.id(); // Os acessadores têm o nome do campoObservação: Os record são imutáveis por padrão, o que quase sempre é o que você quer em uma arquitetura moderna. Se você precisa de mutabilidade, geralmente está modelando uma entidade com estado, não um DTO, e deve usar uma classe tradicional.
Aprenda Java da forma correta:
instanceof: Adeus ao Inferno dos CastsQuantas vezes você já escreveu a mesma sequência cansativa: verificar o tipo e, em seguida, fazer o cast explícito? Agora o compilador faz o cast para você, dentro do bloco, desde que a verificação seja bem-sucedida.
Isso economiza uma linha, mas, mais criticamente, limpa instantaneamente a lógica aninhada.
public void process(Object o) {
if (o instanceof String) {
String s = (String) o; // Cast explícito necessário
System.out.println("Length: " + s.length());
}
}public void process(Object o) {
// 's' é automaticamente convertida para String e está no escopo
if (o instanceof String s) {
System.out.println("Length: " + s.length());
}
// 's' está fora do escopo aqui
}switch: O Simplificador de FluxoAs declarações tradicionais switch eram uma fonte de bugs sutis devido ao fall-through acidental e, além disso, eram apenas declarações — você não podia atribuir o resultado a uma variável.
As expressões switch corrigem isso garantindo um resultado e usando a sintaxe de seta (->) para eliminar a necessidade do break.
String dayType;
switch (day) {
case MONDAY:
case FRIDAY:
dayType = "Busy";
break; // O break é crucial!
case SATURDAY:
case SUNDAY:
dayType = "Weekend";
break;
default:
dayType = "Normal";
}String dayType = switch (day) {
case MONDAY, FRIDAY -> "Busy";
case SATURDAY, SUNDAY -> "Weekend";
default -> "Normal";
};Aprenda Java da forma correta:
As classes seladas, introduzidas no Java 17, não têm como objetivo direto reduzir linhas de código. Elas servem para reduzir possíveis bugs e permitir que o compilador ajude na correção.
Agora você pode declarar explicitamente quais classes ou records podem implementar ou estender um tipo selado, impondo uma hierarquia controlada.
// Impondo que apenas Circle, Square e Rectangle podem ser formas
public sealed interface Shape
permits Circle, Square, Rectangle { }
public record Circle(double radius) implements Shape { }
public final class Square implements Shape { /* ... */ }
// Qualquer classe que não seja explicitamente 'permitida' não pode implementar ShapeA mágica acontece quando você combina isso com uma Expressão switch. O compilador agora pode garantir que você tratou todos os subtipos possíveis, eliminando a necessidade de uma cláusula default defensiva. Isso é poderoso para modelagem Domain-Driven Design (DDD).
Se seu código Java lida com strings de várias linhas — consultas SQL, payloads JSON, trechos HTML ou arquivos de configuração complexos — você provavelmente já teve strings concatenadas feias com caracteres \n inseridos manualmente.
Os Blocos de Texto ("""...""") resolvem esse problema de forma elegante.
String JSON_PAYLOAD = "{\n"
+ " \"name\": \"AccountCreatedEvent\",\n"
+ " \"timestamp\": \"" + now() + "\"\n"
+ "}";String JSON_PAYLOAD = """
{
"name": "AccountCreatedEvent",
"timestamp": "%s"
}
""".formatted(now()); // Funciona muito bem com .formatted()!var): Despoluindo o CódigoEsse recurso, muitas vezes mal compreendido, tem como objetivo reduzir o ruído causado por declarações de tipo redundantes. A chave são as variáveis locais onde o tipo é claro a partir do contexto.
Você economiza na digitação, mas o benefício real são linhas mais limpas, especialmente com genéricos.
Map<String, List<User>> userMap = new HashMap<String, List<User>>();
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
// ...
}// O tipo é óbvio a partir do lado direito (RHS)
var userMap = new HashMap<String, List<User>>();
// Ainda suficientemente explícito para legibilidade
try (var reader = new BufferedReader(new FileReader("data.txt"))) {
// ...
}Sabedoria do Dev Sênior: Use var apenas onde o tipo seja imediatamente óbvio no lado direito (RHS). Não o use para ofuscar tipos de retorno de métodos ou para campos.
Optional: Menos Código DefensivoA classe Optional é essencial para programação no estilo funcional, mas versões mais antigas tornavam tarefas comuns muito verbosas. O Java adicionou métodos mais limpos para tornar o tratamento de erros e efeitos colaterais mais elegantes.
// Tratando um valor ausente com erro
String result = optionalValue.orElseThrow(
() -> new NoSuchElementException("Missing value"));
// Tratando efeitos colaterais de sucesso ou falha
optionalValue.ifPresent(
(v) -> doSomething(v)
);
if (!optionalValue.isPresent()) {
doSomethingElse();
}// Maneira mais limpa de lançar uma exceção
String result = optionalValue.orElseThrow(
NoSuchElementException::new);
// Maneira mais limpa de lidar com efeitos colaterais
optionalValue.ifPresentOrElse(
this::doSomething,
this::doSomethingElse
);Aprenda Java da forma correta:
takeWhile / dropWhile)A API de Streams é a base do Java funcional moderno. takeWhile e dropWhile permitem uma filtragem poderosa, baseada em condições e com curto-circuito.
Em vez de consumir todo o stream com um filter genérico, você pode parar a iteração imediatamente quando uma condição for atendida, levando a um processamento mais rápido de grandes conjuntos de dados.
// Dados: [1, 2, 4, 6, 9, 10, 12]
// takeWhile: Pega elementos *enquanto* o predicado for verdadeiro, depois para.
// Exemplo: takeWhile(n -> n < 5) retorna [1, 2, 4]
// dropWhile: Descarta elementos *enquanto* o predicado for verdadeiro, depois retorna o restante.
// Exemplo: dropWhile(n -> n < 5) retorna [6, 9, 10, 12]Collectors.toUnmodifiableList/Set/Map: Defensivo por PadrãoEm versões mais antigas do Java, os desenvolvedores constantemente se esquecia de encapsular coleções mutáveis em cópias defensivas (por exemplo, Collections.unmodifiableList(...)). Essa é uma fonte clássica de problemas de concorrência e corrupção de estado.
Agora, você pode coletar diretamente em uma lista imutável.
List<String> mutableResults = sourceList.stream()
.filter(...)
.collect(Collectors.toList());
// Mais tarde, você poderia retornar assim, permitindo modificação externa:
// return mutableResults; // PERIGO!
// A maneira defensiva era verbosa:
List<String> safeList = sourceList.stream()
.filter(...)
.collect(Collectors.collectingAndThen(
Collectors.toList(),
Collections::unmodifiableList
));// Uma linha, garantidamente imutável e segura
List<String> safeList = sourceList.stream()
.filter(...)
.toList(); // Esta é a sintaxe simplificada do [Java](https://terminalroot.com.br/java/) 16+
// OU (para [Java](https://terminalroot.com.br/java/) 10+)
List<String> safeList = sourceList.stream()
.filter(...)
.collect(Collectors.toUnmodifiableList());Aprenda Java da forma correta:
Stream::toList(): O Finalizador de StreamsEmbora Collectors.toList() exista há muito tempo, o método de instância Stream::toList() (Java 16+) é uma maneira concisa e sem boilerplate de finalizar um stream em uma List padrão e imodificável.
É o máximo economizador de linhas para a operação de Stream mais comum.
List<String> names = employees.stream()
.map(Employee::getName)
.collect(Collectors.toList());List<String> names = employees.stream()
.map(Employee::getName)
.toList(); // Uma única chamada de métodoA complexidade no software empresarial raramente está na lógica de negócio em si; está no “tecido conjuntivo” — o código repetitivo (boilerplate), as cópias defensivas, as instruções break esquecidas e os casts manuais.
O Java moderno (17+) foi projetado para eliminar esse “tecido conjuntivo”. Ao adotar esses 10 recursos, você não está apenas agradando ao compilador; está libertando seu cérebro da carga cognitiva. O código que você não escreve é código que não pode ter bugs.
Se você mantém uma grande base de código, insisto fortemente para que você pare de usar os padrões antigos e verbosos e comece a migrar seus DTOs para record hoje mesmo. Essa única mudança sozinha lhe dará uma redução imediata e quantificável de 50% na contagem de linhas em seus modelos de dados.
Pare de escrever código descartável. Comece a escrever lógica de negócio.
Via: medium.com/@martinastaberger/