Como foi feito: os exemplos foram preparados intencionalmente pelo assistente de IA para demonstrar duas armadilhas. Executamos os testes localmente em Java 18.0.1.1: a conversão retornou 28 em vez de 29 e a lista do record cresceu de 1 para 2. As verificações das duas correções passaram. Isso não mede a taxa de erros de um modelo nem representa um incidente de produção.
codigo Java gerado por IA pode compilar e ainda conter um erro de calculo ou de mutabilidade. testes com valores monetarios e DTO revelam essas falhas antes do deploy; neste experimento didatico, dois exemplos intencionalmente defeituosos demonstram por que revisar o comportamento importa. Depois de ajustar esse trecho, o proximo passo natural e seguir para Testes no Spring Boot: por que o rollback deixa dados no banco?.
O problema não é a IA “errar feio” o tempo todo. o problema é outro: ela consegue produzir algo que parece plausível, compila sem reclamar e passa batido numa revisão apressada. em produção, isso vira bug de centavos, payload que muda sozinho e suporte tentando entender por que o objeto chegou diferente do que saiu da camada anterior. Esse ponto fica mais claro quando voce conecta com Por Que Aprender Java? 7 Razões para Começar Hoje.
codigo Java gerado por IA: quando compila, mas não entrega o comportamento certo
Em Java, compilar não significa estar correto. isso fica ainda mais claro quando o tema é cálculo monetário ou objetos compartilhados. Um código pode parecer elegante, usar tipos conhecidos e seguir um padrão comum, mas ainda assim errar por arredondamento, conversão numérica ou referência mutável. Esse ponto fica mais claro quando voce conecta com Refresh token no Spring Security: por que o logout pode falhar.
Para um dev que recebe um trecho gerado por IA, a pergunta útil não é “compila?”. a pergunta é “qual comportamento esse código está prometendo e quais invariantes ele quebra?”. essa mudança de foco economiza tempo em revisão e evita que erros simples cheguem até uma API REST, um job batch ou uma integração financeira.
O experimento didático que separa aparência de comportamento
Os dois exemplos abaixo foram montados de propósito para mostrar falhas possíveis em código Java. não é benchmark, não é comparação estatística e não é caça às bruxas. é só um teste de comportamento com dois cenários bem concretos:
1) conversão de valor monetário usando ponto flutuante; 2) record com lista mutável recebida por referência.
Os dois passam pela compilação. os dois podem enganar uma revisão superficial. e os dois deixam um rastro claro quando você executa o código.
Erros comuns em codigo Java gerado por IA com dinheiro e DTO
Uma falha possível em código para dinheiro é usar double, multiplicar por 100 e converter para long ou int. isso parece direto, mas o binário de ponto flutuante não representa 0.29 de forma exata. na prática, o resultado pode sofrer um arredondamento invisível antes da conversão final.
No lado dos DTOs, uma falha possível é aceitar uma lista mutável e guardar a referência diretamente em um record, classe de comando ou objeto de resposta. a estrutura externa muda depois, e o objeto “imutável” deixa de ser confiável. em produção, isso aparece como payload inconsistente, cache com dados inesperados ou validação que passou em um ponto e falhou em outro.
Comparação direta: abordagem pior e abordagem melhor
Abordagem pior: usar (long)(0.29 * 100) para representar 29 centavos e guardar ArrayList direto dentro do objeto. o código é curto, fácil de ler e errado o suficiente para te fazer perder tempo.
Abordagem melhor: usar new BigDecimal("0.29").movePointRight(2).longValueExact() para dinheiro e List.copyOf para proteger a coleção. fica um pouco mais explícito, mas o comportamento é previsível e o bug deixa de ser silencioso.
Esse contraste importa porque em Java a solução mais curta raramente é a mais segura quando o dado tem semântica forte. dinheiro e coleção compartilhada não são casos para “deixar a intuição decidir”.
Erro comum de produção: causa, sintoma e correção
Causa: conversão numérica com ponto flutuante ou reaproveitamento de lista mutável entre camadas.
Sintoma: centavos errados, tamanhos de lista variando depois da criação do objeto e inconsistência difícil de reproduzir em ambiente local.
Correção: usar BigDecimal com string de origem, validação exata com longValueExact() e cópia defensiva com List.copyOf quando o contrato pede isolamento.
Secao pratica com codigo completo
O código abaixo é executável em Java 18.0.1.1. ele mostra, de forma objetiva, o erro e depois a correção. a ideia aqui não é enfeitar; é observar o resultado na saída do programa.
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class IaJavaDemo {
record Order(List<String> items) {}
record SafeOrder(List<String> items) {
SafeOrder {
items = List.copyOf(items);
}
}
public static void main(String[] args) {
long wrong = (long) (0.29 * 100);
long correct = new BigDecimal("0.29")
.movePointRight(2)
.longValueExact();
System.out.println("(long)(0.29*100) = " + wrong);
System.out.println("BigDecimal correto = " + correct);
List<String> base = new ArrayList<>();
base.add("Java");
Order order = new Order(base);
System.out.println("Antes: " + order.items().size());
base.add("Spring");
System.out.println("Depois: " + order.items().size());
SafeOrder safeOrder = new SafeOrder(base);
base.add("Boot");
System.out.println("SafeOrder depois da mutação externa: " + safeOrder.items().size());
try {
List.copyOf(java.util.Arrays.asList("ok", null));
} catch (NullPointerException ex) {
System.out.println("List.copyOf rejeitou null: " + ex.getClass().getSimpleName());
}
}
}Ao executar esse exemplo, o primeiro ponto chama atenção: (long)(0.29*100) retorna 28 em vez de 29. esse detalhe é pequeno no console e grande no financeiro. se essa lógica estiver por trás de um pedido, taxa ou rateio, o bug vira divergência contábil.
No segundo ponto, o record Order(List<String> items) recebe uma ArrayList. depois de adicionar Spring na lista original, order.items().size() muda para 2. o record continua sendo um record, mas não é imune a mutação externa quando carrega uma referência compartilhada.
Já a versão segura com List.copyOf protege a estrutura. a lista interna não acompanha mais alterações posteriores da referência original. e se houver null, a falha acontece cedo, em vez de se esconder até uma serialização, um mapper ou uma regra de negócio mais adiante.
O que esse código ensina na prática
Em cenário de dinheiro, por exemplo um serviço de cobrança, o valor precisa sobreviver inteiro entre fronteiras: input, cálculo, persistência e resposta. se a regra é “29 centavos”, o sistema não pode negociar e devolver 28 só porque um double decidiu ser aproximado.
Em cenário de DTO, por exemplo uma resposta de API com itens de pedido, o consumidor espera que o objeto recebido não mude sozinho depois de pronto. se uma camada de serviço reaproveita a mesma lista e outra parte do sistema continua adicionando elementos, a resposta deixa de representar o instante em que foi criada.
Quando usar e quando evitar cada abordagem
Usar BigDecimal faz sentido sempre que há dinheiro, taxas, descontos ou qualquer número em que centavo importa. mesmo que a regra de negócio pareça simples, o custo de errar é maior do que o custo de escrever duas ou três linhas a mais. o ganho de previsibilidade compensa.
Evite double quando o número representa valor financeiro. em cálculo científico ou leitura aproximada de sensor, a conversa é outra. já em dinheiro, a conta precisa ser exata no que a regra pede, não “próxima o bastante”.
Use List.copyOf quando o objeto precisa preservar a própria coleção sem aceitar mudanças de fora. isso aparece muito em DTOs, records de comando e objetos de consulta. se o contrato da classe é representar um estado fechado, a cópia defensiva combina bem.
Evite List.copyOf quando você realmente quer uma coleção mutável por design. nesse caso, seja explícito no modelo. a pior situação é fingir imutabilidade e manter referência viva por baixo dos panos.
Trade-off real: segurança versus flexibilidade
Há um preço em copiar listas e usar tipos mais rigorosos. você ganha segurança, mas perde um pouco de liberdade de atualização in-place. em muitos sistemas de negócio, esse é um trade-off ótimo. Na prática, em estruturas de domínio e transporte, previsibilidade costuma valer mais do que microeconomia de mutação.
O mesmo vale para a conta monetária. BigDecimal é mais verboso do que double, mas a verbosidade está comprando uma coisa valiosa: consistência. se a camada de domínio lida com dinheiro, a clareza do contrato importa mais que a sensação de simplicidade.
Como testar esse tipo de código antes do deploy
O valor desse experimento não está só na execução manual. ele aponta uma forma de pensar testes: validar comportamento e não só formato. um teste que apenas confere compilação deixa passar exatamente esse tipo de falha.
Em um projeto real, o ideal é cobrir o caminho do valor até a borda do sistema. se a entrada é 0.29, o teste deve afirmar que a saída é 29 centavos. se um record recebe uma lista, o teste precisa verificar se mutações posteriores alteram ou não o estado final, conforme o contrato esperado.
Se o seu time usa Spring Boot, esse cuidado combina bem com testes de integração e verificações de persistência. um próximo passo útil é conectar esse tipo de cenário ao banco de teste e observar se a semântica do objeto continua correta depois da serialização, da transação e do commit. um caminho natural é revisar Testes no Spring Boot: por que o rollback deixa dados no banco?, porque comportamento de teste e comportamento de domínio frequentemente se cruzam quando o bug passa de uma classe para a infraestrutura.
Quem está estruturando a base de Java no time também costuma se beneficiar de uma leitura mais ampla de fundamentos e sintaxe, principalmente quando a discussão sai do “funciona no demo” e entra em “funciona em produção”. nesse ponto, Por Que Aprender Java? 7 Razões para Começar Hoje ajuda a contextualizar por que a linguagem continua tão forte para sistemas que exigem previsibilidade.
codigo Java gerado por IA: por que o teste de comportamento importa mais que a aparência
O que pega nesse tipo de código não é a falta de elegância. muitas vezes o trecho parece limpo, usa APIs modernas e até segue boas práticas parciais. o problema é que o comportamento real foi assumido, não verificado. Na prática, em sistemas com dinheiro, DTO e integração entre camadas, essa diferença custa caro.
Em produção hipotética de e-commerce, por exemplo, um valor de desconto calculado com erro de arredondamento gera divergência entre frontend, pedido e financeiro. em outro cenário hipotético, um DTO de itens de carrinho usa lista mutável e muda depois que a resposta já foi montada. a API responde uma coisa; a memória do objeto conta outra. Na prática, os dois cenários são fáceis de imaginar e chatos de investigar.
Se o código veio de IA, de um colega ou de um snippet antigo, o filtro precisa ser o mesmo: quais invariantes esse trecho preserva? dinheiro precisa ser exato. dTO precisa ser previsível. Na prática, se o código não garante isso, ele pode até compilar, mas ainda está devendo.
Codigo java gerado por ia: referencias externas
Para validar detalhes de implementacao e aprofundar a configuracao, vale consultar a documentacao oficial do Spring Security, o guia de claims no JWT.io e a documentacao do Spring Boot.
FAQ
codigo Java gerado por IA pode compilar e ainda estar errado?
Sim. compilação valida sintaxe e tipos, não regra de negócio. um exemplo clássico é usar ponto flutuante para dinheiro ou manter uma lista mutável dentro de um objeto que deveria ser estável.
Como evitar erro de arredondamento com BigDecimal em Java?
Crie o valor a partir de String, não de double, e use operações explícitas como movePointRight. para conversões exatas, longValueExact() ajuda a falhar cedo quando algo sai do esperado.
List.copyOf resolve mutabilidade em record com ArrayList?
Resolve a mutabilidade da lista em si, criando uma cópia imutável superficial. isso impede mudanças na estrutura da coleção, mas não transforma automaticamente os elementos internos em imutáveis.
Conclusão e próximos passos
O ponto central é simples: o código pode parecer bom, compilar sem drama e ainda carregar falhas de comportamento que só aparecem quando o sistema começa a lidar com dinheiro, coleções e contratos entre camadas. o experimento mostrou isso em dois casos bem comuns: conversão monetária errada e mutabilidade escondida em record.
Se a sua base usa Java no dia a dia, o melhor próximo passo é testar o que importa de verdade: valor, imutabilidade e contrato. faça isso antes de confiar no trecho bonito que apareceu no editor. em produção, um bug de 1 centavo ou uma lista que cresce sozinha costuma custar mais do que alguns minutos extras de revisão.
Para continuar essa linha de leitura, vale olhar como erros de comportamento aparecem em fluxos mais amplos do Spring: revisite Testes no Spring Boot: por que o rollback deixa dados no banco? e, se o assunto do seu time hoje for segurança de sessão, confira também Refresh token no Spring Security: por que o logout pode falhar. a lógica é a mesma: comportamento manda mais do que aparência. Na prática, os proximos passos sao validar esse fluxo no seu projeto, ajustar o caso de uso real e cobrir a implementacao com testes.

1 comentário em “A IA gerou o código Java. Os problemas apareceram nos testes”