Já sabes o que acontece quando o C é compilado para uma arquitectura específica. Já sabes como os dados vivem numa base de dados relacional e como um driver JDBC faz a ponte entre o código e o PostgreSQL. Já sabes como um pedido HTTP viaja pela rede e como um token JWT prova identidade sem estado no servidor. Agora a questão é: como se constrói a aplicação que une tudo isso? A resposta da indústria, para uma fatia enorme do mercado enterprise, é Java com Spring Boot.
Quando escreveste C, o compilador produziu código máquina para uma arquitectura concreta. Esse binário é rápido — fala directamente com a CPU — mas é frágil: compila para x86, não corre em ARM. Compila para Linux, não corre em Windows sem recompilar. Para software de sistemas essa troca faz sentido. Para uma aplicação de negócio que tem de correr no servidor do cliente, no portátil do developer, e na cloud — não faz.
Java resolve este problema com uma camada intermédia: a JVM.
O compilador Java não produz código máquina — produz bytecode,
instruções neutras que a JVM interpreta e traduz para a CPU local em tempo de execução.
O resultado prático: um único .jar corre em qualquer máquina onde
exista uma JVM, independentemente da arquitectura ou sistema operativo.
// Em C: um binário por plataforma
gcc app.c -o app-linux-x86 // só corre em Linux x86
gcc app.c -o app-linux-arm // só corre em Linux ARM
gcc app.c -o app-win-x86.exe // só corre em Windows x86
// Em Java: um único artefacto para todas as plataformas
mvn package
// → app.jar — corre em qualquer JVM, em qualquer arquitectura
java -jar app.jar
Quando escreveste C, geriste memória manualmente: malloc para alocar,
free para libertar. Esqueceres o free é um memory leak.
Libertares duas vezes é undefined behaviour. A disciplina necessária para escrever
C correcto é real — e é uma das principais fontes de CVEs em software de sistemas.
A JVM elimina esta responsabilidade através do Garbage Collector. Quando um objecto deixa de ter referências activas, a JVM liberta a memória automaticamente. Esta abstracção tem um custo em performance e latência de GC — mas para a vasta maioria das aplicações de negócio é uma troca excelente: menos bugs de memória, mais foco na lógica de negócio.
O developer controla cada alocação e libertação. Performance máxima. Erro humano = memory leak, use-after-free, buffer overflow.
A JVM rastreia referências e liberta memória automaticamente. Menor performance bruta. Eliminação de uma classe inteira de bugs.
Em C organizas o código em funções dentro de ficheiros .c.
Em Java a unidade fundamental é a classe — um ficheiro
.java que agrupa dados (campos) e comportamento (métodos).
Uma aplicação Java é uma colecção de classes que colaboram entre si.
A consequência directa é que a main não pode nem deve conter
toda a lógica. Em Java, a main arranca a aplicação e delega
imediatamente para outras classes. Cada classe tem uma responsabilidade clara.
Este princípio — separação de responsabilidades — é o núcleo
do design orientado a objectos.
// Em C: tendência para acumular lógica no main
int main() {
// ligar à BD, processar input, calcular, apresentar — tudo no mesmo sítio
}
// Em Java: main arranca e delega
@SpringBootApplication
public class AutoFlowApplication {
public static void main(String[] args) {
SpringApplication.run(AutoFlowApplication.class, args);
// a partir daqui, o Spring Boot toma conta do resto
}
}
Java como linguagem dá-te classes, tipos, a JVM e o Garbage Collector. Mas construir uma aplicação web de raiz em Java puro — gerir ligações HTTP, parsear JSON, ligar à base de dados, autenticar utilizadores — é uma quantidade enorme de infraestrutura antes de escrever uma linha de lógica de negócio.
O Spring Boot elimina esse trabalho. Quando arrancas uma aplicação Spring Boot tens imediatamente: um servidor HTTP embutido (Tomcat), injecção de dependências, integração com JPA/Hibernate, suporte a JSON, e um sistema de configuração robusto — tudo por convenção, sem XML.
// Uma API REST completa em Spring Boot — 8 linhas
@RestController
@RequestMapping("/api/documents")
public class DocumentController {
@GetMapping("/{id}")
public Document getDocument(@PathVariable Long id) {
return documentService.findById(id);
}
}
@Query em SQL nativo — e precisas de saber o que estás a escrever.@GetMapping e @PostMapping é um mapeamento directo dos verbos HTTP que já conheces. Um @RestController é um handler de pedidos HTTP que responde em JSON..deb para Linux e instaladores Windows.pom.xml, ciclo de vida do build, scopes e auditoria de dependências.@Service, @Repository, @Controller.