Java é uma linguagem grande, famosa, e muito usada. Mas não é, digamos, “charmosa”. Não só eu, mas muita gente reclama que ela é inflexível, sem-graça, e demora a adotar recursos que as concorrentes têm faz tempo (em termos de recursos da linguagem, o C# da Microsoft evoluiu muito mais rápido).
Dependendo do gosto do programador, uma linguagem charmosa seria Python (eu gosto, é quase um pseudocódigo executável), alguma variante de Lisp (os fãs são dedicados, mas eu nunca consegui me adaptar), Ruby (superficialmente lembra Python, é muito flexível, mas sintaticamente é mais complexa), Lua (minimalista e elegante, quase um pseudocódigo executável, como Python), ou até C (reina tranqüilo no seu nicho de infraestrutura, bom para quem gosta do “baixo nível”), C++ (ótimo poder de abstração sem perder as capacidades do C).
Mas aí eu parei para pensar mais friamente: exceto por alguma inveja aqui e ali do C#, Java tem suas qualidades.
Comparando com C e C++:
A tipagem estática e sintaxe simples permite navegação e refatoração fáceis com ferramentas de desenvolvimento. Compare com C++, onde ferramentas de “autocompletar” facilmente falh(av)am porque não entendem as milhares de macros e templates a serem processados nos headers.
O ambiente gerenciado permite reflexão, serialização e stack-traces bem úteis. Já em C e C++, bah… Nessas linguagens, se tiver um core dump para descobrir por que o programa morreu, o programador já acha excelente! Java tem strings Unicode também; em C/C++ tem que correr atrás de alguma lib pra isso.
Em Java até precisa escrever o nome da classe 2 vezes ao instanciá-la, mas diferente de C, C++, e Objective-C, não é necessário ter 2 cópias da assinatura de cada função (nome e parâmetros) uma no cabeçalho e outra na implementação (e a instanciação em Obj-C é pior, pelo que li: Classe* obj = [[Classe alloc] init];
). Depois de um tempo longe do C e C++, tinha até esquecido essa incomodação da replicação entre .h
e .c
.
Em Java dá para deixar outras pessoas mexerem no seu código sem (muito) medo de estragarem seu cuidadoso gerenciamento de memória e ponteiros, depurado com muito suor (entretanto, talvez esqueçam de fechar a conexão com o banco…).
Comparando com as linguagens dinâmicas (Python, Ruby, etc.):
Java é pesado e consome uma enorme quantidade de memória, mas apesar disso, tem o potencial de ser mais rápido que qualquer linguagem dinâmica.
Java é estável, a linguagem não muda radicalmente a cada ano (nem a cada dois anos, talvez mude algo depois de três anos). Dá para começar e terminar seu projeto tranqüilo sem chegar no fim com aquela sensação de estar usando uma versão obsoleta da linguagem.
A questão de reflexão e bibliotecas deixa de ser uma vantagem do Java (como era em relação ao C++), mas em compensação, em Java é muito mais fácil criar interfaces razoáveis e autodocumentadas (por causa das declarações de tipos) entre módulos diferentes da aplicação. Em Python, é um vale tudo: se algum espertinho ou distraído resolver adicionar um atributo de objeto chamado tmp35 no if mais escondido do arquivo A e acessá-lo num tratador de exceção que quase nunca é executado no arquivo B, a linguagem vai aceitar; o atributo vai existir ou não dependendo do if, e o tratador de exceção pode ter um comportamento diferente dependendo disso.
Você queria ter uma boa mensagem de erro mas o próprio tratador de exceção pode jogar uma exceção por causa de uma variável não encontrada, enquanto que em Java um problema desses não passaria do estágio de compilação. Em Java, muito mais problemas são detectados logo na compilação, ou pelo próprio editor que já compila o programa em segundo plano. Geralmente dizem que basta usar testes unitários com as linguagens dinâmicas, mas não sei… Precisaria de muito mais testes (escrever os testes é complicado!), e não daria para esquecer de testar os casos mais excepcionais, já que vários tipos de erro de digitação só são detectados quando o programa executa tal linha. Ao fazer uma grande refatoração numa linguagem com tipos mais estritos, pelo menos temos uma garantia que não deixamos nenhum pedaço do código horrivelmente inconsistente, né?
Comparando com outras linguagens:
Apesar de verbosa, a linguagem Java vem do C++, com práticos atalhos como i++
; i += 2
; a = b = c = 0
; declaração de variáveis em qualquer local da função; operador ternário ?:
; e ganhou um for-each bem antes do C++. Imaginem se Java viesse do Pascal, com variáveis declaradas só no começo das funções, i := i + 1
; e os horríveis begin e end, que embora teoricamente sejam necessários “apenas para instruções compostas”, acabam sendo necessários quase sempre, porque a linguagem não permite fazer muita coisa por linha (nada de v[i++] = w[j++] = x[k++]
).