Esse artigo faz parte da revista Java Magazine edição 12. Clique aqui para ler todos os artigos desta edição

jm12_capa.gif

rincipal style="MARGIN: 0cm 70.85pt 0pt 0cm">Tiger: A Evolução de Java

O próximo grande passo

Conheça as novidades da linguagem Java, com foco na facilidade de programação, e um pouco do "making of" do J2SE 1.5

A plataforma Java introduziu a simplicidade como uma de suas vantagens competitivas originais. Há muito tempo, na época do JDK 1.0, tinha-se uma linguagem razoavelmente simples, uma API minúscula e um ciclo de desenvolvimento trivial. O tempo passou, e hoje Java carrega o peso do próprio sucesso. Existem muitas APIs, gerando uma curva de aprendizado longa para novatos; a linguagem quase não mudou, mas o código das aplicações – cada vez mais complexas – ressente-se de melhorias de sintaxe; e a rotina do desenvolvedor inclui complicações como descritores de deployment e muito código burocrático, que nos força a escolher entre perder muito tempo ou depender de ferramentas que gerem esse código.

Para nossa sorte, a evolução de Java não está parada. Como sabemos, o próximo release (JDK 1.5, codinome “Tiger”) promete muitas melhorias na facilidade de programação. Mas as vantagens não param por aí: existem diversas frentes adicionais no mesmo sentido, tocadas por outras JSRs, além de algumas soluções já disponíveis, que mais desenvolvedores poderiam aproveitar para simplificar muito seu desenvolvimento com Java. Por trás de tudo o que será visto nesse artigo, existe claramente uma visão, compartilhada pelos fornecedores de tecnologia Java (seja a Sun, seus parceiros comerciais, ou grupos open-source), que elege a facilidade de desenvolvimento como a próxima fronteira para expandir ainda mais o mercado de Java.

Sendo justos, nem todos os aspectos “difíceis” do Java são devidos a deficiências; veja o quadro "As prioridades de Java".

Observe que facilidade é uma questão muito relativa e subjetiva: o que é fácil para um programador com curso superior em computação e calejado em C++, pode ser difícil para outro, com menos instrução formal e mais experiência em linguagens e ferramentas de “alta produtividade” (leia-se que privilegiam facilidade de uso e resultados imediatos a todo custo, em geral sacrificando quesitos como paradigma OO, portabilidade, ou facilidade de manutenção).

A boa notícia para os desenvolvedores mais experientes é que muitas melhorias relacionadas à facilidade de uso servirão para evitar a perda de tempo com a parte mais chata e rotineira do desenvolvimento, liberando seus talentos para coisas mais interessantes e produtivas.

A Cultura de Java

Como sabemos, a tecnologia Java foi criada na Sun Microsystems, uma empresa cuja tradição é ligada ao Unix e a produtos de hardware. Não é um pessoal que programava em Basic. A Sun não tinha experiência com tecnologias orientadas para o consumidor leigo ou mesmo para desenvolvedores habituados a ferramentas visuais. Isso se refletiu no Java dos primeiros tempos, quando a única opção de desenvolvimento era a crueza do JDK, oferecendo apenas ferramentas de linha de comando e exigindo configuração de paths, classpaths, properties e que tais.

Note que outros SDKs gratuitos (por exemplo, o do Windows) costumam ser igualmente rústicos, mas, enquanto os vendedores de outras plataformas costumam lançar SDKs juntamente com ferramentas elaboradas (geralmente comerciais), no mundo Java os IDEs sempre correram atrás. Isso só mudou recentemente, quando a Sun começou a disponibilizar uma versão do NetBeans (que é gratuito e open-source) sincronizada com cada novo JDK.

Hoje existem muitos IDEs visuais, tanto comerciais quanto gratuitos, mas essas ferramentas de produtividade às vezes vêm atrasadas. Por exemplo, experimente trabalhar com o JWSDP (Java Web Services Developer Pack), que traz as novas APIs de Web Services. Compilar qualquer “alô, mundo” requer malabarismos com classpath, ferramentas intermediárias (ex.: wscompile), arquivos de configuração e de deployment para algum container etc. Por isso a Sun teve que adotar no JWSDP scripts do Ant (que não é ainda uma ferramenta “oficial” do Java) para a compilação dos exemplos. Desenvolvedores experientes em 5 minutos customizarão esses scripts para os próprios projetos, mas boa parte da complicação não deveria existir para começo de conversa.

Essa defasagem dos IDEs atualmente ocorre apenas com APIs “independentes” (ainda não integradas ao J2SE ou ao J2EE), e parece ser um custo necessário do modelo incremental de evolução de Java. Seria complicado para as empresas atualizar produtos complexos, como IDEs, a cada nova versão de qualquer API. O ideal seria ter um padrão unificado para extensões de IDEs, de forma que cada biblioteca nova ou atualizada que pudesse se beneficiar do suporte dessas ferramentas fosse disponibilizada junto com um plug-in. Por exemplo, a distribuição do JWSDP poderia incluir plug-ins suportando pelo menos funcionalidades essenciais, como a edição de arquivos XML ou a compilação automática de stubs JAX-RPC. A JSR-198 ("A Standard Extension API for Integrated Development Environments"), que está definindo o padrão de plug-ins necessário, tornará esse cenário tecnicamente possível.

O aspecto positivo da maneira como Java evoluiu é que sempre houve um grande cuidado com aspectos formais do projeto da linguagem e das APIs. Por exemplo, Java não somente implementa um bom modelo de orientação a objetos, mas também possui um framework (conjunto integrado de APIs OO) que faz bom uso de abstração, design patterns e boas práticas de projeto OO em geral. Os adeptos de projeto e programação orientada a objetos sempre gostaram dessas qualidades do Java, e os resultados mostram o efetivo valor da arquitetura. Mesmo após oito anos de evolução, alguns upgrades revolucionários e muitas APIs deprecated, a plataforma atual é admiravelmente compatível com todo o legado existente[1]. 

Existem casos, no entanto, em que esse legado atrapalha melhorias, mas são as exceções à regra do bom design. Por exemplo, a evolução das coleções originais do JDK 1.1 (Vector e Hashtable) para as novas collections do Java 2 (List, Map etc.) não pôde ser completa – por exemplo, Properties herda de Hashtable, não sendo possível mudar isso sem quebra de compatibilidade. O problema não é que as collections originais fossem ruins ou limitadas, mas somente que não foram modeladas com interfaces – um erro em se tratando de uma API que obviamente teria que ser muito expandida.

Em outros casos houve até excesso de zelo dos projetistas do Java. Por exemplo, praticamente todas as classes das APIs são thread-safe (com métodos synchronized onde necessário, permitindo o compartilhamento seguro dos objetos entre vários threads). Isso torna a programação concorrente bem mais fácil, mas adiciona um custo em desempenho que pode ser importante em alguns casos. Outro exemplo é a arquitetura do Swing, talvez um dos projetos OO mais radicalmente abstratos já criados. Ao contrário do que muita gente pensa, o “peso” do Swing não é devido à renderização ser feita por código Java, e sim ao fato de que qualquer operação simples invoca muitos métodos polimórficos, cria muitos objetos temporários no heap etc. A API é volumosa, e se, por um lado, permite a desenvolvedores experientes criar GUIs dinâmicas e sofisticadas com grande elegância e bom desempenho, por outro, pode ser um "canhão para matar mosquito" para muitas aplicações.

Java e Açúcar Sintático

A expressão syntax sugar (açúcar sintático) tem conotação negativa na literatura de linguagens de programação. Significa construções não-essenciais do léxico ou da gramática de uma linguagem, que existem somente para “economizar digitação”. O problema é que nem todos concordam sobre quais funcionalidades são suficientemente importantes para merecer uma implementação privilegiada como parte da linguagem, e quais devem ser relegadas às bibliotecas. Este conflito não existiria se as linguagens tivessem mecanismos de extensão excepcionais, mas esses próprios mecanismos são outro ponto de discórdia entre as várias “escolas” de linguagens de programação.

Linguagens como C++, Eiffel e C# suportam a redefinição de operadores (permitindo criar, por exemplo, um tipo complexo que pode ser usado com a mesma sintaxe dos tipos numéricos primitivos); todavia, esse recurso adiciona bastante complexidade à linguagem e tem altíssimo potencial de abuso. E mesmo nas linguagens mais complexas sempre falta algum mecanismo de extensão. Por exemplo, nenhuma das linguagens mencionadas permite ao programador criar suas próprias estruturas de controle. Em um projeto recente, precisei de uma estrutura random-foreach, da seguinte forma:

 

random-foreach (int i : 0 .. array.length-1) {

  // processa array.length[i]

}

 

A necessidade era percorrer todos os elementos do array, porém em ordem aleatória. Existem soluções, como colocar os elementos num ArrayList e embaralhá-lo com Collections.shuffle(), mas nada seria tão elegante quanto a construção mostrada anteriormente, se esta pudesse ser implementada em Java. Isso é possível em linguagens radicalmente dinâmicas como Smalltalk e LISP, mas estas cobram um preço (em desempenho e robustez) por serem tão dinâmicas.

Adoçando o Tiger

Com o Tiger, a linguagem Java finalmente abre a guarda para algumas facilidades de sintaxe na categoria “açúcar sintático”. Os mais ortodoxos poderão torcer o nariz, mas na verdade todas as melhorias adicionadas à nova versão são concessões bastante pragmáticas. São facilidades cuja relação custo/benefício parece ser muito boa. Vamos analisar brevemente – e justificar – cada uma dessas novidades.

Notas:

·         Este artigo não pretende ser um tutorial do Tiger, que inclui muitas outras melhorias não mencionadas aqui – haverá muito tempo para isso. O alvo dessa discussão está nas melhorias de produtividade introduzidas ou habilitadas pela nova versão do J2SE.

·         Nos exemplos existem algumas dependências circulares entre as novas facilidades da linguagem que apresentamos, de forma que você encontrará algumas sintaxes sendo utilizadas antes da seção que as explica. Tentei reduzir essas “referências futuras” ao mínimo, mas não foi possível remover todas as "circularidades", pois é importante ilustrar a integração entre as novas sintaxes, que faz com que o todo seja maior que a soma das partes.

 

...

Quer ler esse conteúdo completo? Tenha acesso completo