A Evolução da Linguagem Java

Propaganda
artigo
A Evolução da Linguagem Java
Veja as mudanças da linguagem para o Java 7 e quais
são as possíveis novidades para o futuro
Roberto Perillo
([email protected])
é bacharel em Ciência da Computação e
está atualmente concluindo o curso de
especialização em Engenharia de Software
do ITA. Trabalha com Java há quase 5 anos,
possui as certificações SCJP, SCWCD e SCJD, e
participa ativamente dos fóruns do JavaRanch.
Já trabalhou com JEE em grandes empresas,
como Avaya e IBM, nesta última foi co-fundador
do time de inovação de ibm.com GWPS Brasil.
Eduardo Guerra
([email protected])
é pesquisador em desenvolvimento de
frameworks, participando de projetos opensource como SwingBean, Esfinge Framework,
ClassMock e JColtrane. Atualmente está
cursando doutorado no ITA, onde também
já concluiu graduação em Engenharia
da Computação e mestrado. Possui as
certificações SCJA, SCJP, SCWCD, SCBCD (1.3
e 5.0), SCJWSD, SCMAD e SCEA e experiência
como arquiteto de software nas plataformas
Java SE, Java EE e Java ME. Atua também como
professor na graduação do ITA e nos cursos de
pós-graduação ITA/Stefanini.
A
linguagem Java é hoje uma das mais utilizadas em todo
mundo. Em 2006, as estatísticas do Sourceforge apontavam
que ela havia ultrapassado a linguagem C++ em número de
projetos. Segundo o site TIOBE Software, que divulga um índice mensal
a respeito da popularidade de linguagens de programação, em julho de
2009, Java é a linguagem mais popular entre os desenvolvedores. Esse
índice se baseia no número de profissionais qualificados, cursos e serviços oferecidos no mercado, e também nas procuras realizadas em sites,
como Google, MSN, Yahoo!, Wikipedia e YouTube. Analisando o histórico
da linguagem neste índice, disponível desde 2001, ela se posicionou
sempre entre a primeira e a segunda posição.
Imagine agora como deve ser difícil realizar alterações em uma linguagem como Java. Cada mudança poderá afetar e ter um grande impacto
sobre um número imenso de projetos e desenvolvedores em todo
36 www.mundoj.com.br
mundo, e por isso mesmo cada uma deve ser realizada com cuidado. Por
exemplo, no Java 5, em que funcionalidades de linguagem foram acrescentadas, diversos programas não compilaram na nova versão devido
a adição da palavra reservada enum, que muitas vezes era utilizada em
identificadores, como para nomes de variáveis.
Neste artigo, é apresentada com exclusividade uma entrevista realizada
com Alex Buckley, o atual responsável na Sun pela linguagem Java e pela
arquitetura da máquina virtual. Nesta entrevista, ele passa um pouco de
sua enorme experiência na evolução da linguagem e dá algumas dicas a
respeito do que podemos esperar de novidade no futuro da linguagem
e da plataforma. O artigo também irá explorar mais a fundo as funcionalidades de linguagem previstas para entrarem no Java 7 e faz algumas
previsões a respeito do que se pode esperar para outras futuras versões.
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
Entrevista com Alex Buckley
'JHVSB&EJUPSDIFGFEB.VOEPKFNTVBDPOWFSTBDPN"MFY#VDLMFZ
'JHVSB&EJUPSDIFGFEB.VOEPKFNTVBDPOWFSTBDPN"MFY#VDLMFZ
.VOEPK – Por favor, descreva sua posição e suas responsabilidades
na Sun Microsystems, Inc.
"MFY#VDLMFZ – Meu nome é Alex Buckley e sou o “teologista computacional”
da linguagem Java e da máquina virtual Java (JVM). Dia a dia, isto significa que
sou responsável pela especificação da linguagem Java e pela especificação
da JVM. Estas definem, de uma forma independente de implementação, o
significado da linguagem Java e da JVM. Eu não me preocupo com o comportamento do “javac”, ou qualquer das bibliotecas de classes, por exemplo. Eu só
me preocupo com a definição da linguagem Java em si, o que ela faz e por que
ela o faz de tal forma; e o mesmo para a máquina virtual. Obviamente, existem
grandes sobreposições entre o design da linguagem e a máquina virtual, então
manter as duas especificações sincronizadas tem sido historicamente grande
parte do trabalho. Com mais linguagens começando a serem executadas na
JVM, as especificações podem começar a ir em diferentes direções.
.VOEPK – Que tipo de coisas você busca em conferências acadêmicas como o ECOOP (European Conference on Object-Oriented
Programming) e o OOPSLA (International Conference on ObjectOriented Programming, Systems, Languages, and Applications)?
"MFY #VDLMFZ – Nos dias de hoje, a orientação a objetos tem um papel
muito importante na indústria. Outros paradigmas de programação, como a
programação funcional ou lógica, têm seus seguidores, porém a orientação a
objetos é o paradigma predominante. Congressos como o ECOOP e o OOPSLA
apresentam muitos trabalhos baseados em linguagens predominantes na
indústria, como Java ou C#. O que eu procuro nestes congressos são artigos
que descrevam o núcleo de uma característica de linguagem. Não é um problema se esta característica não se pareça com Java, ou se é expressa em uma
linguagem de brincadeira, ou até mesmo se é expressa formalmente em uma
linguagem matemática. Eu não preciso saber que “esta é uma extensão Java e
Todos os anos, vários eventos sobre programação orientada a objetos são
realizados ao redor do mundo, onde são apresentados diversos trabalhos
focados ou baseados na linguagem Java. Particularmente, no meio científico, os que mais se destacam são o ECOOP (European Conference on Object
Oriented Programming) que ocorre na Europa e o OOPSLA (International
Conference on Object-Oriented Programming, Systems, Languages, and
Applications) que acontece nos Estados Unidos. No OOPSLA do ano passado, mais especificamente no dia 22 de outubro, a revista Mundoj teve
oportunidade de realizar uma entrevista exclusiva com Alexander Buckley,
que é o atual responsável pelas especificações da linguagem Java e pela
arquitetura da JVM. Nesta conversa, foi possível obter várias informações
interessantes, como fatos ocorridos há mais de 10 anos que fazem parte
da história da linguagem e indícios do que ainda está para entrar nela.
Foi possível também ter noção do quão difícil é evoluir uma linguagem
quando ela já está sendo amplamente utilizada na indústria.
a ideia na linguagem seria de tal forma”, porque na prática, como as características são em linguagens reais é um tópico muito complicado. Por exemplo,
você não pode inventar suas próprias palavras-chave porque isto quebraria
código antigo. Eu procuro em artigos publicados no ECOOP e no OOPSLA pelo
núcleo de uma ideia que possa ser adicionada à linguagem, então como elas
são expressas não é um problema.
Que tipos de características são interessantes? Bem, eu diria características de
linguagem que suportam melhor modularidade de programas, assim como
características de linguagem que suportam melhor análise de programas.
Muitas pessoas não sabem, ou até saibam, mas não percebam o quão profundo isto é. A linguagem Java é quase única pelo fato de que a especificação da
linguagem Java requer um compilador para executar alguns tipos de análise
de programa. Na análise de alcance, não se pode ter declarações que nunca
serão executadas. Na análise de declaração, deve-se sempre atribuir valores
a variáveis finais e locais antes de usá-las. Isto na verdade é mandatório na
especificação da linguagem Java. Se houver uma análise de programa útil
que nós acharmos que vá beneficiar todos os desenvolvedores Java, há uma
grande possibilidade de colocá-la nos padrões.
.VOEPK – Há muitas boas ideias sendo apresentadas nestes congressos. Quanto tempo leva para uma boa ideia ir do meio acadêmico para a indústria?
"MFY#VDLMFZ – Um enorme exemplo de uma característica proposta no
meio acadêmico que foi adicionada à linguagem é, claro, generics. Assim
que o Java foi lançado, o meio acadêmico ficou muito animado. Philip
Wadler e Martin Odersky começaram a pensar como deveriam ser os
tipos genéricos em Java. Como deveria ser a implementação? Teríamos
que mudar só a linguagem ou a JVM também? Isto foi no final de 1996,
quase tão logo o Java foi lançado.
37
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
Os generics foram algo em que o meu antecessor se envolveu muito. Isto
foi na JSR 14, em 1998. Martin Odersky reescreveu o compilador Java,
que se chamava GJ na época, para suportar generics, e aquela implementação dele se tornou o “javac”. Então o “javac” 1.3 era o compilador
do Martin. Claro, os generics foram novamente estendidos para suportar
os wildcards, e isto foi novamente o resultado de um trabalho acadêmico, de Mirko Viroli e Atsushi Igarashi, sobre variâncias, que são representadas na linguagem Java como “?”, “? extends” e “? super”. Este é um caso
interessante no qual a pesquisa havia começado há anos, e assim que
começamos a tentar aplicar o conceito a programas reais e a bibliotecas
Java, descobrimos que o trabalho acadêmico não havia ido tão longe e
precisa de mais desenvolvimento. Assim surgiram os wildcards.
.VOEPK – O oposto também acontece? Por exemplo, a indústria começa a usar algo e o meio acadêmico percebe que precisa pesquisar
o assunto?
"MFY#VDLMFZ – Esta é uma pergunta interessante! No mundo do Java,
muita inovação vem da implementação dos padrões ao invés dos próprios padrões. O grande objetivo do Java SE, Java ME e do Java EE é que
existam padrões, e se você escreve seu código de acordo com estes padrões, você pode usar as bibliotecas e APIs destes padrões. O código vai
funcionar com qualquer implementação, então muita inovação está em
fazer implementações realmente eficientes ou fazê-las rodar em várias
plataformas ou dispositivos bem pequenos. Os padrões evoluem, por
natureza, de forma mais lenta do que a implementação, que pode usar
vários truques.
.VOEPK – Isso aconteceu com anotações, talvez?
"MFY#VDLMFZ – Anotações na prática são populares e certamente habilitam muitos trabalhos acadêmicos, porque esses trabalhos precisam de
metadados. Metadado não é um conceito muito complexo, e as anotações da linguagem Java são bem simples. O que os acadêmicos fazem
com as anotações e o que é representado com as anotações é muito interessante. Eu diria que há funcionalidades na linguagem que suportam
mais pesquisas acadêmicas, como o uso acadêmico das anotações. E a
plataforma em si, tornando-se open-source com o JDK aberto, permite
que as pessoas peguem o compilador Java, a JVM, o compilador Just-inTime e façam experimentos neles.
.VOEPK – O quão difícil é evoluir uma linguagem? Podemos comparar esta evolução com a evolução de uma API, por exemplo?
"MFY #VDLMFZ – Existem alguns aspectos da linguagem que podem ser
evoluídos. Existe a sintaxe da linguagem, o sistema de tipos da linguagem e
o comportamento das instruções da linguagem. Muitas pessoas perguntam:
“É possível adicionar uma palavra-chave para fazer isso ou aquilo?”, mas é bastante complicado mudar a sintaxe ou a gramática da linguagem Java. Não é
possível simplesmente adicionar novas palavras-chave, pois qualquer palavrachave que você possa imaginar, alguém em algum lugar a estará usando como
nome de variável. No passado, pudemos verificar que no momento em que
uma nova palavra-chave é adicionada, alguns programas são quebrados, e não
38 www.mundoj.com.br
compilarão na última versão da linguagem Java. É muito mais difícil evoluir a
sintaxe da linguagem do que as pessoas imaginam.
É como evoluir a sintaxe da linguagem se você adiciona palavras-chave que só
agem como palavras-chave quando for preciso, e em todos os outros lugares
do programa, elas agem como identificadores. Então, se elas agem como nome
de variável, ou nome de classe, ou nome de método hoje, elas continuarão
agindo amanhã. Estas palavras-chave agem como palavras-chave somente
em locais bem específicos, talvez no topo do arquivo-fonte, em que precisa
ser uma palavra-chave. Realmente, é possível evoluir a sintaxe da linguagem,
e aprendemos uma lição ao adicionar “enum” do Java 1.4 para o Java 1.5, que
causou verdadeiras dores de cabeça a muitas pessoas. Aprendemos uma lição
e não cometeremos este erro novamente. Não vamos, no futuro, adicionar
palavras-chave que quebram o código-fonte. Evoluir a sintaxe é complicado e
aprendemos como fazê-lo melhor.
Evoluir o sistema de tipos da linguagem, e muitas propostas acadêmicas estão
nesta área, é a coisa mais complicada. É muito difícil mudar o sistema de tipos
Java, porque o sistema de tipos da linguagem Java (a) é refletido no sistema de
tipos da JVM; (b) é embutido nas bibliotecas de reflexão, então seria necessário
mudá-las também; e (c) novamente, sempre tem implicações em programas
existentes, e a Sun não quer quebrar o código das pessoas só porque há algum
novo tipo de sistemas mais elaborado.
Mas é possível adicionar um novo tipo. O debate sobre closures foi efetivamente sobre se devemos adicionar funções à linguagem Java. A questão é se estaríamos adicionando algo tecnicamente seguro. Os generics sem os wildcards
são seguros, mas muito restritos. Por isso, os wildcards foram adicionados, e há
restrições nos wildcards que confundem as pessoas, mas que precisam existir,
caso contrário você pode escrever um programa que compile, mas que trave
em tempo de execução.
Há algumas propostas que são aparentemente fáceis, mas que têm comportamentos complicados em tempo de execução. As pessoas dizem “tudo bem,
não tem problema”, mas qualquer expert em sistemas de tipos irá lhe dizer que
se você adiciona tipos estáticos, então o comportamento em tempo de execução deve ser previsível. É uma área muito complicada que tem um impacto
enorme na plataforma e em programas. Assim, somos muito cautelosos ao
fazer mudanças nessa área.
.VOEPK – Em relação a aspectos, quando iremos vê-los nativamente
na linguagem Java? Estamos perto ou longe disso?
"MFY#VDLMFZ – Todos têm suas ferramentas, frameworks ou funcionalidades favoritas, que gostariam que fossem tiradas de uma API e fossem embutidas na linguagem Java. A dificuldade é que isto tornaria a
linguagem Java mais difícil para todos aprenderem. Alguns gostariam de
ver um framework orientado a aspectos adicionado à linguagem Java,
outros gostariam de ver um framework orientado a recursos adicionado à linguagem Java. Uma linguagem não é nem uma aplicação nem
uma API. Uma linguagem é melhor quando é menor e aplicações e APIs
são melhores quando são maiores, pois assim podem ter mais poder e
consequentemente terão mais usuários. Você só precisa se preocupar
com as partes da API que você usa. Por outro lado, uma linguagem é
melhor quando é menor, pois todo programador Java no mundo precisa
entender efetivamente o significado de cada funcionalidade.
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
Então, se você faz dos joint points ou point cuts ou advices elementos de
primeira classe na linguagem Java, você irá fazer duas coisas: primeiro,
irá forçar todos os desenvolvedores Java a aprender aspectos. E mais,
irá forçá-los a aprender aspectos como eles eram no dia em que você
os embutiu na linguagem Java. Isto efetivamente pára novas pesquisas
úteis sobre aspectos. Claro, existirão novos artigos sobre aspectos no
futuro, mas uma vez que eles foram embutidos na linguagem, é a sua
única chance de fazê-lo. Não dá para voltar e mudar depois disso.
.VOEPK – É uma estratégia ter a JVM suportando outras linguagens,
com outras funcionalidades, para que o Java não precise mudar
tanto?
"MFY#VDLMFZ – A JVM sempre foi capaz de executar outras linguagens-fonte, contanto que exista um compilador para elas. Não há
nada na JVM que funcione somente para a linguagem Java. Podemos dizer que existem aproximadamente 100 linguagens-fonte que
compilam para a JVM. Outra coisa a dizer é que muitas destas linguagens dinâmicas são mais velhas que o Java em si, como o Ruby,
por exemplo. Então, não é surpresa que muitas linguagens além do
Java têm sido executadas na JVM há muitos anos.
Linguagens como Scala, que ainda estão em desenvolvimento, podem compilar para a JVM, então é possível comunicar-se com elas
através de código Java, o que é muito interessante. É ótimo quando
as pessoas olham para essas linguagens e expandem suas mentes,
vendo novas formas de programar. Porém lembre-se de que estas
linguagens estão livres para que seus designers removam funcionalidades a qualquer momento, ou redefinam funcionalidades.
A Sun fica satisfeita quando pessoas escrevem outra linguagem que
compila para a JVM e que tem o mesmo desempenho que código
Java. A JVM é uma plataforma facilmente gerenciável, com muitas
APIs. Tem uma ótima tradição quanto à segurança, e suas implementações atualmente têm ótimos compiladores Just-in-Time.
Frequentemente, um compilador Just-in-Time na JVM consegue
produzir código de máquina mais eficiente que um compilador C.
E é interessante quando os criadores de outras linguagens também
dizem que estão animados por verem suas linguagens tendo múl-
/PWJEBEFTRVFEFWFNBQBSFDFSOP+BWB
Após a adição de novas funcionalidades de linguagem no Java 5, houve
uma grande discussão a respeito do que poderia aparecer nas novas
versões. Apesar de algumas das funcionalidades nas seções seguintes
estarem praticamente confirmadas no Java 7, a verdade é que nada é
certo ainda. As funcionalidades que serão apresentadas dão uma noção
de como será “a cara” da linguagem na sua próxima versão.
Este artigo se limita a abordar as funcionalidades relacionadas com
mudanças na linguagem, porém diversas outras mudanças, como, por
exemplo, em APIs e na máquina virtual, também estão previstas. Uma
que vale a pena ser comentada é o Projeto Jigsaw (que em português
tiplas implementações, não somente um interpretador C nativo,
mas também rodando na JVM, pois a JVM está em todos os lugares;
em telefones celulares, em grandes servidores de aplicação. Então,
todos ganham!
.VOEPK – O que mais pode ser adicionado ao que você disse no começo, sobre a JVM e a linguagem Java indo em direções diferentes?
"MFY #VDLMFZ – Posso dizer que o que está acontecendo na JVM para
suportar linguagens dinâmicas é muito interessante. Acontece que, hoje
em dia, é possível rodar JRuby, Jython e outras linguagens dinâmicas na
JVM. Elas eram bem lentas, e hoje têm um bom desempenho. Agora a
pergunta é se podemos fazê-las rodar tão rápido quanto se fossem código Java. E o que estamos fazendo é colocar ganchos na JVM, para que
alguém, como o implementador JRuby ou Jython, possa instruir a JVM
sobre como otimizar código compilado do JRuby ou do Jython. O código
compilado Java não precisa usar estes ganchos, já que o compilador
Java frequentemente efetua otimizações entre o código-fonte Java e os
bytecodes Java. Os bytecodes Java, sua forma, seu tamanho, é de certa
forma entendido nativamente por compiladores Just-in-Time. Mas ao
rodar classes compiladas do JRuby ou Jython, o compilador Just-in-Time
precisa de uma pequena ajuda para otimizar estes bytecodes. Está é a
proposta da JSR 292. Dá até para imaginar o compilador Java também
usando este mecanismo, sem mudanças na linguagem Java, somente
como uma técnica de otimização.
Também surge a ideia de que a linguagem Java em si poderia ser mais
dinâmica. O que isto significa? Significa, por exemplo, que código Java
poderia chamar métodos em código Ruby ou Python, compilados pelo
JRuby ou Jython. Métodos Ruby e Python não possuem tipos em seus
códigos-fonte. Atualmente, tudo no Java assume que o que está sendo
chamado possui tipos. Achamos que provavelmente vai ser muito útil
poder efetuar chamadas entre linguagens, principalmente quando estas
outras linguagens estiverem rodando bem rápido na JVM e quando houver mais códigos escritos nestas linguagens rodando na JVM.
seria algo como serra tico-tico), que visa a modularização da JDK 7. Este
trabalho permitirá, por exemplo, que uma aplicação seja implantada
apenas com os componentes da JDK que ela realmente precisar, o que
poderá escalar a JDK para dispositivos menores e mais simples.
Uma novidade interessante para os fãs das linguagens dinâmicas que
também está prevista para a JDK 7 é um melhor suporte da máquina
virtual para outras linguagens (ver última pergunta da entrevista com
Alex Buckley). O objetivo é a criação de extensões para a máquina virtual
que suportem a implementação de linguagens “não-java” em um nível
de desempenho próximo da própria linguagem Java.
As próximas subseções abordam as funcionalidades da linguagem que
provavelmente irão "dar as caras" no Java 7. Serão abordadas as anota-
39
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
ções de tipo e outras possíveis mudanças em anotações, o novo suporte
a programação modular e outras pequenas melhorias de linguagens
agrupadas no chamado Project Coin.
t
"OPUBÎÍPFNUJQPTEFBSSBZT
// array de arrays de documentos somente leitura
@ReadOnly Document [][] docs1;
// array somente leitura de arrays de documentos
Document @ReadOnly [][] docs2;
// array de arrays somente leitura de documentos
Document [] @ReadOnly [] docs3;
t
"OPUBÎÍPFNDPOWFSTÜFTEFUJQPT
myStr = (@Readonly String) obj;
"OPUBÎÍPFNSFTVMUBEPTSFDFCJEPTEFDPOTUSVUPSFT
Person p = new @Immutable Person();
Anotações em Tipos
A JSR 308, intitulada de “Type Annotations”, tem como objetivo estender o
sistema de anotações existentes para que elas possam aparecer em qualquer
local onde possa ser utilizado um tipo. No Java SE 6, é possível anotar declarações de classes, métodos, atributos e variáveis, e com essa adição, será possível
no Java SE 7 que as anotações possam ser utilizadas para outros fins.
A aplicação mais imediata desse novo mecanismo seria para o uso na JSR 305
“Annotations for Software Defect Detection”, que possui como objetivo a definição de anotações para verificações estáticas em tempo de compilação, visando a
detecção de problemas que hoje acabam sendo detectados apenas em tempo
de execução. Um exemplo seria a anotação @NonNull na declaração de variáveis,
para as quais uma ferramenta faria uma verificação em tempo de compilação
e acusaria um erro se existe a possibilidade da mesma assumir o valor nulo.
Segundo o próprio documento que propõe a adição, o uso desse mecanismo
de detecção de defeitos seria limitado sem as anotações de tipo, pois se perderia
facilmente o rastro das variáveis anotadas quando fosse feito o uso de tipos genéricos, quando fosse feita a invocação de um método em um objeto, quando fosse
efetuado um cast, quando uma classe fosse estendida etc.
Para se ter uma ideia de como seria a sintaxe desse novo tipo de anotação,
abaixo segue uma lista com alguns exemplos:
t "OPUBÎÍPFNQBSÉNFUSPTHFOÏSJDPTQBSBDMBTTFTQBSBNFUSJ[BEBT
List<@NonNull String> list;
t
"OPUBÎÍP FN QBSÉNFUSPT HFOÏSJDPT QBSB JOWPDBÎÜFT EF NÏUPEPT PV
construtores
obj.<@NonNull String>metodo(“string”);
t
t
"OPUBÎÍPFNWFSJmDBÎÜFTEFUJQPTDPNPPQFSBEPSJOTUBODFPG
if(str instanceof @NonNull String){ … }
t
"OPUBÎÍPFNSFGFSÐODJBTMJUFSBJTEFDMBTTFT
Class<@NonNull String> c = @NonNull String.class;
t
"OPUBÎÍPFNBDFTTPBNFNCSPTFTUÈUJDPT
@NonNull Type.field
A primeira impressão que se tem quando do primeiro contato com a sintaxe
desse novo tipo de anotações é que o código ficará extremamente confuso
com a adição dessas novas informações. Imagine, por exemplo, a definição da
variável abaixo:
@Immutable Map<@NonNull String,
@NonEmpty List<@Readonly Document>> files;
Por esse motivo, é possível encontrar diversas opiniões em blogs na
internet criticando essa nova feature da linguagem como os posts
“When You Should Jump? JRS 308. That's When.” e “What Hath Java
Wrought” que argumentam que o código pode ficar extremamente
confuso e verboso com o uso desse novo tipo de anotação. Com a
discussão iniciada, outros se posicionam a favor, como o post “JSR
308 Animosity”, que critica essa “animosidade” gerada a essa nova
funcionalidade da linguagem.
t
"OPUBÎÍPQBSBSFTUSJÎÜFTEFUJQPTFQBSBXJMEDBSETFNUJQPTHFOÏSJDPT
class BeanPresenter<E extends @Readonly Bean> { … }
Collection <? super @Readonly Bean> col;
t
"OPUBÎÍPFNQBSÉNFUSPTEFUJQPT
interface StaticList<@Readonly E> { … }
t
"OPUBÎÍPFNUJQPTJNQMFNFOUBEPTPVIFSEBEPT
class UnmodifiafleList<T> implements @Readonly List<@Readonly T>
{…}
t
"OPUBÎÍPFNDMÈVTVMBTUISPXTEFFYDFÎÜFT
void createConnection() throws @Critical IOException { … }
t
"OPUBÎÍPOBTJOTUÉODJBTOBTRVBJTPTNÏUPEPTFTUÍPTFOEPJOWPDBEPT
Na verdade, todo método de instância recebe um parâmetro implícito
'this'. Esta anotação é no tipo de 'this' e é colocada entre a lista de parâmetros e a cláusula 'throws'.
public String toString() @ReadOnly { … }
Apesar de podermos pensar que uma @NonNull String é um tipo que
não pode receber atribuições de uma outra variável do tipo String (sem
anotações) ou @Nullable String, a ideia é que essa verificação seja feita
por plugins que irão atuar em tempo de compilação. Na arquitetura da
máquina virtual, nada seria alterado no sistema de tipos da linguagem.
t
"OPUBÎÍPOPUJQPEFSFUPSOPEFVNDPOTUSVUPS
class Statue {
@Immutable Statue() { … }
}
Apesar da primeira aplicação pensada para essas anotações ser seu
consumo estático em tempo de compilação, elas também poderão
ser acessadas em tempo de execução. Como a API Reflection não dá
acesso ao corpo dos métodos, em alguns tipos de uso essas anotações
40 www.mundoj.com.br
Na verdade, essa nova funcionalidade é de uso opcional da mesma forma que o Generics, o que significa que ninguém será obrigado a utilizar
essas anotações se não quiser. Ela permite apenas que novas metainformações possam ser adicionadas aos tipos, porém essa JSR não trata
do significado ou semântica dessas anotações (o que fica, por exemplo,
a cargo da JSR 305). Assim também como com a utilização de Generics,
com o uso dessa funcionalidade pode-se fazer coisas muito interessantes, porém a codificação se torna mais difícil e o código mais poluído.
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
não poderão ser recuperadas em tempo de execução, como seu uso
em variáveis locais, com o operador instanceof, em casts de tipos
etc. Porém, em outros casos, como seu uso em geral na assinatura de
métodos e na declaração de tipos e variáveis de classe, será possível a
recuperação. A modificação que será realizada na API Reflection é bem
pequena: basicamente a classe Type passará a implementar a interface
Utilizando Type Annotations para
problemas reais
Para quem quiser experimentar as Type Annotations, existe uma ferramenta
preliminar que permite o uso desse tipo de anotação. O Checker Framework
(ver referências) é uma ferramenta que provê plug-ins para o javac, que verificam e previnem erros em tempo de compilação. Um desenvolvedor pode utilizar esse plug-in sem que seus companheiros de trabalho precisem utilizá-lo,
bastando que eles não acionem os plug-ins no momento de executar o javac.
O Checker Framework vem com tudo que você precisa, incluindo ferramentas
que facilitam a criação de novos verificadores.
As anotações que já são suportadas pelo Checker Framework podem ser consideradas como uma prévia das que virão na JSR 305 “Annotations for Software
Defect Detection”. Esse tipo de verificação é uma ferramenta muito valiosa para
arquitetos que desejam assegurar que determinadas propriedades no código
sejam seguidas por todos os desenvolvedores em um projeto maior. Esse framework possui os seguintes tipos de verificação:
t /VMMOFTT$IFDLFS este verificador através de anotações como @Nullable e @NonNull checa se em algum ponto do código existe a possibilidade de se invocar um método em uma referência nula. Esse tipo de prática
evita que em tempo de execução seja lançada a indesejável e famosa
NullPointerException. Existem anotações para opções mais avançadas,
como @LazyNonNull, que permite que uma instância seja nula, porém
não depois que ela for inicializada.
t *OUFSOJOH $IFDLFS esse verificador irá procurar por usos incorretos
do operador == e do método equals() para realizar a comparação de
igualdade entre objetos. Interning, também conhecido como canonicalização, é um padrão de projeto no qual sempre que duas referências
podem ser consideradas iguais, elas estarão apontando para a mesma
instância. A anotação @Interned marca esse tipo de referência e evita
que erros como o representado abaixo aconteça:
Integer x = new Integer(23);
Integer y = new Integer(23);
Apesar da JSR 308 se chamar “Type Annotations”, ela também abrange
em seu escopo outras possíveis modificações no sistema de anotações
da linguagem Java. Na verdade, esse nome foi adotado para evitar um
nome vago como “Extensions to Java’s Annotation System” e pelo fato da
principal mudança ser a inclusão das anotações de tipo. A JSR 308 não
possui a intenção de ser a última JSR sobre a definição de anotações na
linguagem Java e é aceitável que sejam deixadas questões pendentes
para serem consideradas em novas JSRs, que serão incorporadas em
versões futuras da linguagem.
Abaixo seguem algumas possíveis modificações no sistema de anotações
AnnotatedElemment, que possui métodos que permitem a recuperação de anotações.
O quadro “Utilizando Type Annotations para Problemas Reais” irá
apresentar exemplos de aplicação desse tipo de anotação, para que os
leitores possam avaliar os ganhos que se pode ter com essa adição em
relação à complexidade que é adicionada na sintaxe da linguagem.
System.out.println(x == y); // imprime false!
t
t
.VUBCJMJUZ$IFDLFSeste verificador, através de anotações como @Mutable, @Immutable e @Readonly, procura erros que apontam locais que
modificam indevidamente propriedades de objetos. O uso desse verificador evitaria, por exemplo, que uma lista ou seus objetos recuperados
de um cache, fossem modificados externamente a ele de forma indevida, causando efeitos colaterais indesejados a outros clientes desse cache.
-PDL$IFDLFS o objetivo desse verificador é prevenir alguns erros de
concorrência. A anotação @GuardedBy deve ser utilizada em tipos de
variáveis que só devem ser acessadas quando um determinado lock é
obtido. A anotação @Holding já anota métodos que só devem ser chamados se um determinado lock foi obtido por quem o está chamando.
O objetivo desse pequeno resumo não foi ensinar com detalhes como utilizar
cada uma das anotações dos verificadores, mas fornecer uma visão geral do
tipo de coisa que poderá ser implementada como esse novo recurso. O link
para o manual do Checker Framework pode ser encontrado nas referências
deste artigo.
No material pesquisado, não foi encontrado nenhum exemplo referente à utilização das anotações de tipo em tempo de execução, porém analisando a API
do EJB 3, por exemplo, é possível identificar alguns possíveis usos. A anotação
@ApplicationException deve ser utilizada em classes de exceções, de runtime
ou não, que devem ser encaradas como erros de negócio. Quando uma exceção desse tipo é lançada, só é dado o rollback da transação quando a anotação
possui o atributo 'rollback = true'.
Com esse tipo de abordagem, uma mesma classe de exceção não pode ser utilizada em situações em que o comportamento em relação ao rollback ou não
das exceções seja diferente. Com o uso de anotações em tipos, um método que
lança exceções poderia ter em sua própria assinatura, na declaração das exceções, a definição de quais delas devem fazer com que o container faça ou não
o rollback da transação corrente. Obviamente, essa funcionalidade é apenas
uma previsão, mas ilustra como uma nova gama de opções e possibilidades
pode ser aberta com essa adição à linguagem.
da linguagem. Algumas são bem suaves e contêm pequenas modificações que visam simplesmente simplificar a sintaxe, enquanto outras
são modificações mais profundas e exigem que internamente grandes
modificações sejam feitas.
t "OPUBÎÜFTNÞMUJQMBTEPNFTNPUJQPna linguagem Java, não é
permitido que uma mesma anotação seja utilizada duas vezes. Esse
tipo de restrição faz com que seja necessária a criação de uma anotação com uma lista da anotação que se deseja repetir. Isso pode
ser visto, por exemplo, na anotação @NamedQuery da API JPA que
precisa ser encapsulada pela anotação @NamedQueries, conforme
o exemplo abaixo:
41
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
@NamedQueries({
@NamedQuery(name = "todasPessoas",
query = "SELECT p FROM Pessoa p"),
@NamedQuery(name = "pessoaNome",
query = "SELECT p FROM Pessoa p WHERE p.nome = :nome")
})
public class Pessoa { … }
Com a implementação dessa modificação, será possível eliminar a
anotação @NamedQueries e colocar várias anotações @NamedQuery
diretamente na classe, conforme o código a seguir:
@NamedQuery(name = "todasPessoas", query = "SELECT p FROM Pessoa p")
@NamedQuery(name = "pessoaNome",
query = "SELECT p FROM Pessoa p WHERE p.nome = :nome")
public class Pessoa { … }
t
t
/PWPTMPDBJTQBSBBOPUBÎÜFTtambém estão sendo estudados
outros locais, além dos apresentados nas anotações de tipo,
para a adição de anotações. Dentre eles estão anotações em
comandos ou em um grupo de comandos, como loops e blocos. Os defensores dessa proposta argumentam que esse tipo
de anotação traria benefícios para verificações de atomicidade
e concorrência. Dentre as alterações necessárias estariam a definição da sintaxe e do formato do arquivo .class para armazenar
essa informação.
Dentre outras possibilidades também analisadas estão as anotações para expressões, para as quais ainda não se tem uma
aplicação comprovada que justifique sua adição, e anotações
para apenas certos tipos de comandos, que não apresenta muitos benefícios em relação à proposta mais geral.
)FSBOÎB FOUSF BOPUBÎÜFT atualmente, uma anotação não
pode herdar características de outras, o que dificulta a extensão de processadores de anotações, que devem atuar em um
conjunto fixo de anotações. O recurso utilizado para contornar
esse problema é meta-anotar uma anotação, para que o interpretador possa ler essa meta-anotação, como utilizado em frameworks como o Hibernate Validator e o JColtrane.
A ausência de herança também limita bastante a expressividade das anotações. Considere uma anotação @PreCondition que
recebe uma anotação @Expression com uma expressão a ser verificada:
@PreCondition(@Expression(“a == b”))
public void method() { … }
Sem herança, é impossível definir outra anotação que possa ser colocada
no lugar de @Expression, como uma anotação que faz uma negação ou
uma anotação que junta duas expressões como no exemplo abaixo:
@PreCondition(@And(exp1 = @Expression(“a < b”),
exp2 = @Expression(a < c))
public void method() { … }
Existem duas soluções descritas na definição da JSR que estão sendo
consideradas para a herança: a possibilidade de uma anotação estender outras anotações e a possibilidade de uma anotação estender e
implementar interfaces.
t "OPUBÎÜFTSFDVSTJWBTexistem algumas limitações na expres42 www.mundoj.com.br
sividade das anotações, sendo exemplos o fato de uma anotação não poder receber uma anotação arbitrária como argumento e o fato de uma anotação não poder possuir uma definição
recursiva. Esses tipos de estrutura já se provaram eficientes em
outras tecnologias, como, por exemplo, XML e YAML. Para que
isso seja possível, seria necessário para finalizar uma recursão
outras adições, como a possibilidade de possuir argumentos
nulos na anotação (que hoje também não é possível, somente
valores default).
t "SHVNFOUPTQPTJDJPOBJT a sintaxe das anotações quando elas
recebem um argumento pode ser simplificada quando a mesma
possui a propriedade value, o qual pode ser omitido. Exemplificando, no lugar de definir @Annotation(value = 13), é possível
colocar apenas @Annotation(13). Infelizmente, quando é necessário definir mais de um argumento, essa simplificação não é
possível e a sintaxe fica mais verbosa. Está sendo estudada uma
forma de definir uma posição para os argumentos de forma que
os nomes possam ser omitidos.
Outra questão sendo abordada nesse tópico é a obrigatoriedade do nome value para a propriedade default, cujo nome pode
ser omitido. Muitas vezes, esse nome não é significativo em relação ao domínio. A ideia é permitir que na definição da anotação seja definido, possivelmente através de uma anotação como
@ValueMember, qual é o campo que será considerado caso o
nome do argumento não seja definido explicitamente.
t "OPUBÎÜFT FN IJFSBSRVJBT atualmente, é possível definir
uma anotação que será herdada pelas subclasses de uma classe anotada através do uso da anotação @Inherited. Porém,
essa herança é somente das anotações da superclasse e anotações definidas nas interfaces, por exemplo, não são herdadas.
Poderia também ser interessante que anotações pudessem ser
herdadas nos membros da classe, como em métodos sobrepostos e construtores.
t "OPUBÎÜFT EFGBVMU diversas APIs possuem anotações de métodos que, ao serem definidas na classe, servem como uma definição default para os métodos da classe. Um exemplo seria a
anotação @TransactionAttribute da especificação EJB 3. Porém,
esse tipo de comportamento é implementado pelo componente
que processa as anotações e não existe um mecanismo padrão
para esse tipo de definição, que pode diminuir e simplificar o
código. Uma possível mudança seria a definição de uma anotação para possibilitar esse tipo de definição, conforme o exemplo
abaixo:
@DefaultAnnotation(@MyAnnotation(“a”))
class Exemplo { … }
Para que esse tipo de definição seja possível, também seria preciso
que a funcionalidade que permite anotações possa possuir como
argumentos anotações de tipos arbitrários.
Como foi dito por Alex Buckley em sua entrevista, a introdução de anotações na linguagem Java permitiu o desenvolvimento de diversos trabalhos
interessantes que utilizavam esse mecanismo para incorporar novas
informações nas classes, permitindo o desenvolvimento de novas funcionalidades. Essas adições nas anotações visam uma maior expressividade
das informações e simplificação na sintaxe, além de introduzi-las em novos
locais abrindo uma nova gama de possibilidades para sua utilização.
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
Suporte de linguagem à modularização
As JSRs 277 (focando em deployment e empacotamento) e 294 (focando em
modularidade de APIs em tempo de desenvolvimento) introduzem o conceito
de superpackages. O problema que este conceito procura solucionar diz respeito a relações hierárquicas entre pacotes. Por exemplo, ao tornar uma classe
pública, ela passa a fazer parte de uma determinada API.
Listagem 1. Exemplo de superpackage.
superpackage com.mundoj.java7 {
// Pacotes membros
member package com.mundoj.java7;
member package com.mundoj.java7.interview;
member package com.mundoj.java7.typeannotations;
Atualmente, não existe uma forma nativa de dizer que uma classe, mesmo
pública, é pública somente para alguns pacotes e não acessível (algo como
o modificador de acesso default) para outros pacotes. Existem ferramentas,
como JDepend, por exemplo, que podem prover esse tipo de verificação antes
ou depois da compilação, mostrando que existe no mercado essa necessidade.
Os superpackages fornecem uma forma de expressar essa relação hierárquica
entre pacotes, que podem ter membros públicos para a implementação de
determinados pacotes, porém que não devem ser visíveis para outros pacotes.
Assim, pacotes que estão organizados dentro de um superpackage podem
acessar classes públicas entre si, mas ao mesmo tempo, pacotes que estão
fora deste superpackage não podem acessar essas classes, a menos que estas
sejam exportadas.
O exemplo da listagem 1 mostra como os superpackages devem aparecer na
linguagem:
Na verdade, um superpackage é uma unidade de compilação onde serão
definidos os pacotes que terão acesso a classes públicas de outros pacotes e
quais classes públicas poderão ser vistas de fora dessa unidade de compilação.
Para se definir um superpackage, será preciso criar um arquivo super-package.
java no local onde este será definido. Para o exemplo da Listagem 1, o caminho completo do arquivo é com/mundoj/java7/super-package.java. Nele, é
definido que os pacotes com.mundoj.java7, com.mundoj.java7.interview e
com.mundoj.java7.typeannotations farão parte deste superpackage, assim
como os superpackages com.mundoj.java5 e com.mundoj.java6. A classe
HelloWorld é exportada, o que significa que esta classe estará disponível fora
deste superpackage. O pacote membro com.mundoj.java7.interview também
é exportado, o que significa que seus membros públicos também poderão ser
acessados de fora deste superpackage, ao contrário do pacote com.mundoj.
java7.typeannotations, que não é exportado.
Mesmo sendo uma característica nova na linguagem, não será obrigatória
sua utilização, podendo assim ser ignorada. Isto é essencial para que haja
compatibilidade com código já desenvolvido, o que é uma das principais preocupações ao se introduzir uma nova funcionalidade na linguagem. Essa é uma
característica que possibilita a relação entre pacotes em nível de classe, mas
ainda não existe nada que possa informar que um método deve ser público
para determinados métodos e não acessível para outros métodos.
Pequenas melhorias na linguagem – Project Coin
O objetivo do Project Coin é determinar o conjunto de pequenas alterações de linguagem que deve ser adicionado ao Java 7. A submissão
de propostas foi até o dia 30 de março deste ano e os interessados
deveriam preencher um formulário com diversos itens que descrevem
a mudança desejada. Essa proposta deve descrever os seus benefícios e
as desvantagens da proposta, além de apresentar alternativas existentes
sem mudanças na linguagem. Também deveria ser mostrado um exemplo simples, com o objetivo de exemplificar rapidamente o uso da nova
funcionalidade, e um exemplo avançado, que deve mostrar como seria o
// Superpackages membros
member superpackage com.mundoj.java5;
member superpackage com.mundoj.java6;
// Classe exportada (pode ser acessada de fora do superpackage)
export com.mundoj.java7.HelloWorld;
// Pacote exportado
export package com.mundoj.java7.interview;
}
funcionamento em casos mais complexos.
Outra parte importante da proposta é a que analisa o impacto que elas
teriam no que já existe hoje, como na gramática da linguagem e no
formato das classes compiladas em bytecode. Também se deve levar em
consideração como essa funcionalidade pode ser testada, se é necessário
o suporte de bibliotecas e se são necessárias alterações na API de reflexão. Mudanças em outras ferramentas e partes da plataforma como serialização e o javadoc também devem ser consideradas. Na parte final da
proposta, um quesito que é crítico na aceitação da mudança diz respeito
à compatibilidade: essa mudança quebra algum código existente? Como
programas feitos na versão anterior interagem com esta funcionalidade?
As seções seguintes descrevem algumas das propostas do Project Coin
mais comentadas e com mais probabilidade de serem incorporadas na
linguagem Java. É importante ressaltar que essas ainda são propostas e
que, ao serem consideradas dentro de uma JSR, podem sofrer modificações, serem deixadas para versões futuras ou mesmo serem definitivamente descartadas.
B
&TUSVUVSBTTXJUDIDPNTVQPSUFQBSB4USJOHT
Atualmente, estruturas switch do Java suportam somente os tipos primitivos byte, short, char, int, as classes wrapper (Character, Byte, Short,
Integer) e constantes enum. Alguns desenvolvedores utilizam o hashCode (que na verdade é um inteiro) de variáveis String para sua utilização
no case do switch, simulando de certa forma a utilização de Strings em
estruturas switch. Um dos problemas dessa abordagem é que o código
fica pouco legível. Muito possivelmente, a versão 7 da linguagem Java
suportará também Strings em estruturas switch de forma nativa. Desta
forma, será possível escrever o código apresentado na Listagem 2.
A estrutura de controle switch não é uma das favoritas na comunidade de
desenvolvimento, sendo que seu uso é classificado por alguns como uma
má prática. O próprio livro de Martin Fowler sobre refatoração fala que
em cada switch existe um "mal cheiro", para o qual vale a pena verificar
se não deve ser utilizado polimorfismo. Dessa forma, pode-se questionar
se realmente vale a pena investir nessa modificação, que talvez incentive
ainda mais o uso dessa estrutura.
43
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
Listagem 2. String em uma estrutura switch.
Listagem 5. Chamadas encadeadas.
public void ouvirMusica(String nome) {
switch (nome) {
case “Beto”: {
System.out.println(“Vamos ouvir John Lennon ou Pink Floyd?”);
break;
}
case “Guerra”: {
System.out.println(“Vamos ouvir Jewel ou Alanis Morissette?”);
break;
}
default: {
System.out.println(“Vamos ouvir Led Zeppelin!”);
}
}
public class Pessoa {
C
0QFSBEPSFTEFDPNQBSBÎÍPFNFOVNT
Enums são ordenados por natureza. Atualmente, para se comparar constantes enum, utiliza-se comumente o método compareTo(), que é disponível implicitamente a tipos enum. Embora funcione, é pouco intuitivo e
pouco legível. Por exemplo, atualmente, podemos comparar constantes
enum conforme apresentado na Listagem 3.
private String nome;
private int idade;
// Métodos getter e setter omitidos
}
public void cumprimentar() {
System.out.println(“Ola, meu nome eh “ + nome + “!”);
}
// Instanciando um objeto da classe Pessoa
Pessoa pessoa = new Pessoa();
// Chamadas encadeadas
pessoa.setNome(“Beto”).setIdade(26).cumprimentar();
já existentes, causando sintaxes e usos inesperados da mesma. Isso pode
gerar uma fonte de novos bugs e até mesmo quebrar código já existente,
o que é algo indesejado em qualquer nova funcionalidade da linguagem.
Como essas funcionalidades ainda são apenas propostas, é preciso esperar para ver se ela será mesmo implementada ou se haverão mudanças
na ideia original.
Listagem 3. Comparação de constantes enum com o método compareTo().
E
*OGFSÐODJBEFUJQPTFNDMBTTFTHFOÏSJDBT
enum Tamanho {PEQUENO, MEDIO, GRANDE}
Uma das ideias que poderão surgir como melhoria na linguagem é a inferência de tipos ao instanciar classes genéricas. Por exemplo, atualmente,
para se instanciar um HashMap (que é uma classe genérica), é preciso declarar a variável com as mesmas informações do tipo. Um artifício comumente utilizado por desenvolvedores é a utilização de fábricas estáticas
para que isso não seja preciso. A Listagem 6 ilustra as duas abordagens.
Tamanho meuTamanho = Tamanho.GRANDE;
Tamanho seuTamanho = Tamanho.MEDIO;
if (meuTamanho.compareTo(seuTamanho) > 0) {
System.out.println(“Minha camisa vai ficar um pouco grande em voce!”);
}
Na Listagem 3, o resultado do método compareTo() é 1 porque a
constante GRANDE aparece uma posição depois da constante MEDIO.
Assim, se existisse outra constante chamada MUITO_GRANDE depois da
constante GRANDE, e seu valor fosse atribuído à variável meuTamanho,
então o resultado da chamada do método compareTo() seria 2. Além da
forma apresentada na Listagem 3, os operadores de comparação == e !=
também podem ser utilizados. A partir do Java 7, muito possivelmente,
também poderão ser utilizados os outros operadores de comparação,
como exemplificado na Listagem 4. Espera-se também que o desempenho dessa comparação seja melhorado com essa modificação.
Listagem 4. Comparação de constantes enum no Java 7.
enum Tamanho {PEQUENO, MEDIO, GRANDE}
Tamanho meuTamanho = Tamanho.GRANDE;
Tamanho seuTamanho = Tamanho.MEDIO;
if (meuTamanho > seuTamanho) {
System.out.println(“Minha camisa vai ficar um pouco grande em voce!”);
}
D
.ÏUPEPTWPJEJNQMJDJUBNFOUFSFUPSOBOEPUIJT
Outra nova funcionalidade interessante que possivelmente aparecerá
na próxima versão da linguagem são as chamadas encadeadas, em que
métodos void implicitamente retornarão this (que se refere sempre ao
objeto atual). Isto tornará a “fluent interface” mais fácil de ser utilizada. A
Listagem 5 mostra um exemplo de chamadas encadeadas.
Uma das críticas a essa funcionalidade é que ela irá alterar o uso de APIs
44 www.mundoj.com.br
Listagem 6. Instanciando classes genéricas.
// Criando um HashMap a partir do Java 5
Map<Integer, String> mapa = new HashMap<Integer, String>();
// Criando um HashMap utilizando uma fábrica estática
Map<Integer, String> outroMapa = makeHashMap();
// Fábrica estática de HashMap
static <K, V> HashMap<K, V> makeHashMap() {
return new HashMap<K,V>();
}
A partir do Java 7, a classe genérica possivelmente poderá assumir
automaticamente a mesma parametrização do tipo da variável. Assim,
a expressão de criação de instâncias de classes genéricas será da forma
mostrada na Listagem 7.
Listagem 7. Instanciando classes genéricas a partir do Java 7.
Map<Integer, String> mapa = new HashMap<>();
List<String> lista = new ArrayList<>();
Além disso, a partir do Java 7, as informações sobre os generics poderão estar
disponíveis também em tempo de execução. Quando os generics foram introduzidos na linguagem, foi definido que suas informações estariam disponíveis
somente em tempo de compilação, para que houvesse compatibilidade com
códigos criados antes dos generics. Na próxima versão do Java, existe a possibilidade que essas informações sobre o tipo genérico de uma instância também
possa ser acessada em tempo de execução através da API Reflection.
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
F
$MÈVTVMBDBUDIBQSJNPSBEB
Possivelmente, a cláusula catch de tratamento de exceções terá duas mudanças significativas. A primeira delas é que será possível “pegar” mais de uma
exceção por bloco e tratá-las igualmente. Muitas vezes, o tratamento que
precisa ser dado a exceções em um bloco que pode lançar mais de um tipo de
exceção é igual para todas. Isso é especialmente problemático quando essas
exceções são de hierarquias distintas. Por exemplo, atualmente, é comum
encontrarmos um código como o da Listagem 8.
Listagem 8. Mesmo tratamento aplicado a mais de uma exceção.
try {
return klass.newInstance();
} catch (InstantiationException exception) {
throw new AssertionError(exception);
} catch (IllegalAccessException exception) {
throw new AssertionError(exception);
}
A partir do Java 7, deverá ser possível “pegar” várias exceções na mesma
cláusula catch e tratá-las da mesma forma. A Listagem 9 mostra como
isso poderá ser feito.
Listagem 9. Tratamento de exceções no Java 7.
try {
return klass.newInstance();
} catch (InstantiationException | IllegalAccessException exception) {
throw new AssertionError(exception);
}
Além disso, a cláusula catch também deve sofrer outra alteração significativa.
Em algumas situações, muitos desenvolvedores escolhem definir somente
uma cláusula catch para tratar quaisquer exceções que possam ser lançadas
a partir de um bloco try, e após tratá-las, relançam estas exceções. Para isso,
basta definir uma única cláusula catch com um tipo mais amplo do que as exceções que podem ser lançadas no bloco try (como Throwable, por exemplo).
O problema é que neste caso, o tipo da exceção pode se tornar mais amplo do
que as exceções indicadas na assinatura do método, o que torna impossível
relançar as exceções no momento do tratamento. Por exemplo, o código
apresentado na Listagem 9 causará um erro de compilação.
Listagem 9. Erro de compilação ao lançar uma exceção mais ampla do
que as indicadas na assinatura do método.
public void metodoArriscado() throws IOException, RemoteException {
try {
// Bloco try lançando vários tipos de exceções
} catch (Throwable exception) {
// A exceção poderia ser tratada aqui
throw exception; // Erro de compilação: Unhandled exception type
Throwable
}
}
O erro de compilação mostrado na Listagem 9 acontece porque o tipo
Throwable é mais amplo do que IOException ou RemoteException, que
são as exceções que o método pode lançar. A partir do Java 7, será possível aplicar o mesmo tratamento para quaisquer exceções e relançá-las,
mesmo que o tipo indicado na cláusula catch seja mais amplo do que os
indicados na assinatura do método. Por exemplo, o código da Listagem 10
mostra como esse tipo de comportamento será implementado no Java 7.
Listagem 10. Código válido a partir do Java 7.
public void metodoArriscado() throws IOException, RemoteException {
try {
// Bloco try lançando vários tipos de exceções
} catch (final Throwable exception) {
// A exceção poderia ser tratada aqui
throw exception; // Sem erro de compilação
}
}
Ao adicionar a palavra-chave final à declaração da exceção na cláusula
catch, o compilador entende que as únicas exceções verificadas que
podem estar sendo tratadas são as lançadas pelo bloco try, e desde que
essas exceções estejam declaradas na assinatura do método, é possível
relançá-las, mesmo que o tipo indicado na cláusula catch seja mais amplo do que os indicados na assinatura do método.
G
&YUFOTJPO.FUIPET
Uma vez que uma interface está definida, não é possível adicionar novos
métodos sem quebrar as implementações existentes. Isso porque as classes
que implementam a interface não possuem implementações dos novos
métodos. Por exemplo, ao adicionar novos métodos à interface java.sql.
ResultSet, todas as implementações atuais se tornariam inválidas. Como
forma de contornar este problema, em algumas APIs existem métodos
estáticos utilitários que criam novas funcionalidades, como exemplo, pode
ser citada a classe Collections. Esses métodos são pouco convenientes de
serem utilizados e dificultam a legibilidade do código.
Uma proposta de funcionalidade feita por Neal Gafter, chamada de Extension Methods, seria a possibilidade de adicionar métodos estáticos a
interfaces já existentes. A versão mais simples dessa proposta, exemplificada na Listagem 11, permite que métodos importados estaticamente
possam ser utilizados como membros do seu primeiro argumento.
Listagem 11. Exemplo de métodos de extensão.
// Importação estática de métodos
import static java.util.Collections.sort;
...
List<String> list = new ArrayList<>();
// É como se o método sort() fizesse parte da interface List, mas na verdade
// em tempo de compilação isso é convertido para a chamada sort(list)
list.sort();
Essa proposta gerou discussões como possíveis conflitos de nome gerados por importações estáticas e a possibilidade de adicionar métodos
em classes com o modificador 'final', o que poderia gerar uma nova fonte
de bugs em aplicações. Como forma de contornar esses problemas, foi
proposto que os métodos nos quais isso poderia ser utilizado deveriam
ser marcados através de uma nova sintaxe ou através de uma anotação.
Outra modificação na proposta original seria a dos métodos invocados
dessa forma possuírem uma sintaxe diferenciada, como list.do.sort() ou
list->sort().
Essas propostas entram em conflito com um dos objetivos de Neal Gafter
quando fez a proposta, que era de simplificar esse tipo de chamada sem
modificar a sintaxe da linguagem. Devido a essas questões, talvez essa funcionalidade acabe sendo deixada de fora, porém isso só o tempo irá dizer.
45
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
0RVFQPEFWJSEFQPJTEP+BWB
Apesar das mudanças do Java 7 parecerem significativas, ainda existem
diversas propostas de mudanças que não entrarão nessa versão
e que muitos apostam que no futuro podem ser incorporadas na
linguagem. As duas subseções seguintes irão falar um pouco sobre duas
funcionalidades sobre as quais existe bastante discussão de quando e
como elas serão inseridas na linguagem. A primeira delas são as closures,
cuja não-inclusão no Java 7 foi a grande decepção da comunidade. A
segunda funcionalidade é a programação orientada a aspectos, que é
um paradigma que vem ganhando cada vez mais adeptos.
Closures
Embora mencionado na entrevista, os closures muito provavelmente aparecerão na linguagem somente em alguma versão posterior ao Java 7. Esta funcionalidade (ou pelo menos algo parecido) já é suportada em várias linguagens
atualmente, a maioria delas dinâmicas. Quase todas as linguagens que foram
introduzidas há menos de dez anos suportam algo do tipo. Ainda não existe
um consenso sobre como eles aparecerão na linguagem Java; atualmente
existem várias propostas, sendo três delas principais.
Existem várias definições para closure, sendo que a mais importante é função
anônima. A teoria da Ciência da Computação chamaria isso de expressão
lambda, e na verdade este conceito não é novo; datando de trabalhos teóricos
da década de 1930. As implementações mais antigas e importantes foram nas
linguagens Scheme e Smalltalk. Um fato curioso é que praticamente todas
as linguagens que podem ser executadas na JVM, exceto a linguagem Java,
possuem algo parecido com closures.
Embora ainda não exista sequer uma JSR para os closures, é possível ter uma
ideia de como essa funcionalidade poderia ser inserida na linguagem. A Listagem 12 dá o exemplo baseado em uma das propostas, de como os closures
poderiam ser implementadas. Nesse exemplo, closure é definida como um
tipo que recebe parâmetros e retorna um resultado. É como um trecho de código que pode ser passado como parâmetro e possui acesso a elementos locais
relativos a onde a closure foi definida. Assim, closure é uma função anônima,
que pode ou não definir parâmetros e até variáveis internas, e pode aparecer
na forma de atribuição ou ser somente uma expressão de resultado.
Este tipo de funcionalidade seria de grande utilidade, por exemplo, na API de
concorrência. Uma Thread poderia ser criada a partir de uma closure com o
código que ela deveria executar. O uso de closures tornaria o código menos
verboso e mais simples de ser entendido.
Não está no escopo deste artigo descrever com detalhes uma ou mais
propostas de implementação de closures na linguagem Java (mesmo
porque isso por si só já daria um grande artigo). Nosso objetivo é apresentar de uma forma breve o que são as closures e tentar especular um
pouco a respeito de sua implementação nativa na linguagem.
Houve uma grande decepção na comunidade a respeito das closures
não terem sido incluídas dentre as funcionalidades do Java 7, pois foram
feitos diversos protótipos e foi criada uma grande expectativa a respeito.
Na conversa da equipe da revista com Alex, ele deu a entender que as
closures muito provavelmente estarão no futuro da linguagem. Dentre
os fatores que pesaram para deixá-las fora do Java 7 está a questão de
que quando uma funcionalidade é adicionada na linguagem, não é mais
possível adotar uma abordagem diferente e cria-se um compromisso de
46 www.mundoj.com.br
Listagem 12. Exemplos de Closures.
// Um closure que soma dois números
{int, int => int} soma = {int x, int y => x + y};
int total = soma.invoke(2, 2);
// Um closure que não retorna valor; somente efetua uma operação
{String => void} cumprimentar = {String nome =>
System.out.println(“Ola, “ + nome);};
cumprimentar.invoke(“Beto”);
compatibilidade em todas as versões futuras. Com a diversidade das propostas, talvez tenha se percebido que se deve estudar mais a fundo qual
seria a forma mais adequada de introdução de closures na linguagem.
Aspectos nativos na Linguagem Java?
A programação orientada a aspectos é um paradigma de programação (porém
que alguns consideram apenas uma nova técnica de modularização) que tem
como objetivo a separação dos interesses transversais em uma aplicação. Os
interesses transversais caracterizam requisitos funcionais ou não-funcionais
que normalmente estão espalhados pelo código, pois estão presentes em
diversos pontos da aplicação. Exemplos comuns desse tipo de interesse são
segurança, transacionalidade e logging, porém existem diversos exemplos
de requisitos funcionais que também possuem essa característica. Como está
fora do escopo deste artigo descrever esse tipo de paradigma, sugere-se aos
leitores que quiserem se aprofundar no tema a leitura de material a respeito.
No Brasil e na América Latina, um dos principais fóruns acadêmicos na área de
aspectos é o LA-WASP (Latin-American Workshop on Aspect-oriented Software Development). No ano de 2008, esse evento contou com o painel “Adoption
of AOSD in Industry”, em que renomados profissionais e pesquisadores da área
discutiram sobre a adoção dos aspectos pela indústria. O painel (figura 2 –
participantes citados da esquerda para direita) contou com o professor Paulo
Borba, UFPE, como moderador e com a participação de Flávia Raimone, da
JBoss Brasil e desenvolvedora do JBoss AOP, com o professor Kevin Sullivan, da
University of Virginia, e com Paulo Merson, do Software Engineering Institute
(SEI), Universidade Carnegie Mellon. Houve certo consenso de que a adoção
desse paradigma de programação pela indústria ainda é modesto, porém muitos projetos utilizam softwares que possuem o uso de aspectos encapsulados
dentro de sua implementação. Um grande exemplo é o próprio servidor de
aplicações JBoss.
Este painel foi citado, pois uma das perguntas feitas aos participantes foi a
respeito do que é necessário para que esse paradigma seja mais adotado pela
indústria. Uma das respostas foi o suporte nativo à programação orientada a
aspectos pela linguagem Java. Infelizmente, pela conversa com Alex Buckley, é
possível perceber que isso é algo que ainda está longe de acontecer.
Ao ser perguntado sobre esta possibilidade, a resposta de Alex foi que, embora os aspectos já sejam bastante maduros, ao colocá-los na linguagem, isto
significaria que todos os desenvolvedores Java precisariam aprender sobre o
assunto, desde desenvolvedores de dispositivos móveis até programadores de
supercomputadores. Ele citou Bjarne Stroustrup (o desenvolvedor da linguagem C++), que há algum tempo falou sobre as propostas de melhorias que ele
recebe e leva para o C++ International Working Group. Ele disse publicamente
que, se uma proposta não é útil para pelo menos 200 mil desenvolvedores,
esta proposta não será nem considerada. No contexto da linguagem Java, este
número pode ser projetado para mais ou menos dois milhões de desenvolvedores. Por esta razão, tão raramente uma proposta de melhoria é aceita.
"SUJHPt"&WPMVÎÍPEB-JOHVBHFN+BWB
Outra questão que deve ser considerada é que hoje Java é ensinada em
diversas universidades do mundo como primeira linguagem de programação. A adição desses novos conceitos nativamente na linguagem
aumentaria sua complexidade e dificultaria seu aprendizado. Se para o
paradigma orientado a objetos foram necessários diversos anos de sua
adoção na indústria para o amadurecimento de certos conceitos, imagine
para a orientação a aspectos que ainda colhe seus primeiros frutos de sua
utilização com sucesso no mercado.
Na academia, existem várias pesquisas sobre o assunto, que procuram, por
exemplo, definir o significado dos chamados adendos (advices) e como
expressar melhor os pontos de junção (joint points) de um aspecto. A incorporação dos aspectos de forma nativa, provavelmente iria frear pesquisas sobre
novas formas de expressar aspectos, prendendo a linguagem Java àquela
implementação em todas as versões subsequentes por questões de compatibilidade. De certa forma, ao adicionar uma nova funcionalidade, a linguagem
está concordando em suportá-la para sempre.
Existem diversas implementações de aspectos na linguagem Java, podendo
ser citados como exemplos o AspectJ, o Spring AOP e o JBoss AOP. O AspectJ é
uma das implementações mais populares e mais completas, que define uma
nova sintaxe para aspectos, porém em sua última versão, também suporta o
uso de anotações para algumas coisas. O Spring AOP utiliza a própria linguagem Java para as definições realizando configurações adicionais em seus
arquivos XML ou utilizando anotações. Ainda existem diversas opções para
os aspectos serem agregados às classes (processo conhecido como weaving),
como em tempo de compilação, em tempo de carregamento e em tempo de
execução. Que tipo de abordagem é mais adequada para a linguagem Java?
Apesar da tecnologia de aspectos já ter amadurecido bastante nos últimos
anos, será que a comunidade está preparada para escolher uma delas para ser
incorporada à linguagem, abandonando as outras abordagens e tendo que
suportar para sempre a que foi escolhida? Esse foi o tipo de indagação que Alex
Buckley apresentou sobre o assunto em sua conversa com a revista.
A implementação de aspectos dentro de uma linguagem como Java não é
apenas uma adição pontual na linguagem como as outras funcionalidades
apresentadas neste artigo, e sim uma mudança profunda que afetaria o
sistema de tipos e a própria arquitetura da máquina virtual. Segundo Alex,
adicionar aspectos, pontos de junção e adendos como tipos da linguagem é
algo complicado, principalmente quando é preciso manter a compatibilidade
com o código legado.
Porém os fãs de aspectos não devem ficar decepcionados com a notícia, pois
a máquina virtual Java está dando cada vez mais um suporte melhor a outras
linguagens. Como foi citado, no Java 7 está se trabalhando para que a invocação de métodos de outras linguagens não-Java tenham um desempenho
similar ao das invocações nativas. O próprio AspectJ pode ser considerado uma
linguagem que compila para bytecode e executa dentro da máquina virtual.
Dessa forma, o fato de Java ainda não ter planos de suportar nativamente
aspectos, não significa que não podemos utilizar aspectos com a linguagem
Java, e sim que talvez ainda não seja a hora de uma implementação ser fixada
e de todos os desenvolvedores precisarem aprender esses novos conceitos.
Considerações finais
As alterações realizadas na linguagem no Java 5 trouxeram diversas lições.
Uma delas foi que evoluções na linguagem podem trazer diversos benefícios, como os tipos genéricos, que ajudaram na criação de um código mais
seguro, e as anotações, que criaram diversas novas possibilidades através da
'JHVSB-"8"41o1BJOFMoi"EPQUJPOPG"04%JO*OEVTUSZw
adição de novas informações às classes. Outra lição foi que é preciso ter muito
cuidado com essas alterações, para que elas sejam compatíveis com código
já existente. Como foi dito na entrevista, a adição da palavra-chave 'enum'
quebrou muitos códigos que utilizavam essa palavra como um identificador.
Este artigo apresentou com exclusividade uma entrevista com Alex Buckley,
que falou sobre sua experiência na evolução da linguagem Java e a respeito
do que podemos esperar para o seu futuro. Também foram vistas as principais funcionalidades de linguagem que devem entrar no Java 7, assim como
certa previsão sobre quando funcionalidades como closures e aspectos
devem aparecer nativamente na linguagem.
Apesar de Alex Buckley ter dito que uma linguagem é melhor quando ela
possui menos funcionalidades, é possível perceber pelas respostas e pelas
propostas de funcionalidades para o Java 7 que a linguagem não está no caminho da simplicidade. Em uma entrevista com James Gosling realizada por
Paulo Silveira e Guilherme Silveira em um JavaOne foi possível perceber essa
mesma tendência. As novas funcionalidades certamente são interessantes
e permitem, por exemplo, a detecção prematura de defeitos e uma melhor
modularização. Isso revela uma tendência em evoluir a linguagem na busca
de uma maior segurança de código mesmo que isso torne a codificação mais
complexa, o que acaba indo na direção oposta de outras linguagens que procuram cada vez mais a simplificação na busca de uma maior produtividade.
Vale a pena lembrar que, neste momento, as funcionalidades apresentadas
ainda são apenas propostas, sendo que algumas delas não possuem nem JSR
ainda. Dessa forma, se você quer participar dessa evolução e dar sua opinião
sobre como deve ser a implementação em cada uma delas, é só se envolver e
dar sua contribuição. O futuro do Java, na verdade, está em nossas mãos!
Referências
t (SÈmDPEFQSPKFUPTQPSMJOHVBHFNEFQSPHSBNBÎÍPOP4PVSDF'PSHFoIUUQXXXDTCFSLFMFZ
edu/~flab/languages.html
t 8IFO :PV 4IPVME +VNQ +34 5IBUhT 8IFO IUUQXXXNJDIBFMOZHBSEDPN
CMPHXIFO@TIPVME@ZPV@KVNQ@KTS@@UIUNM
t 8IBU)BUI+BWB8SPVHIUoIUUQCDTRVBSFECMPHTQPUDPNXIBUIBUIKBWBXSPVght.html
t +43"OJNPTJUZoIUUQXXXDPODVSSFOUBõBJSPSHKTSBOJNPTJUZ
t 5IF $IFDLFS 'SBNFXPSL .BOVBM o IUUQHSPVQTDTBJMNJUFEVQBHKTSDVSSFOUDIFDLFST
manual.pdf
t 5ZQF"OOPUBUJPOT4QFDJmDBUJPO+43
oIUUQHSPVQTDTBJMNJUFEVQBHKBWBSJKBWBBOOPtation-design.pdf
t i5IFSFhTOPUBNPNFOUUPMPTFwo.BSL3FJOIPMET#MPHoIUUQCMPHTTVODPNNSFOUSZKJHTBX
t 0QFO+%,o1SPKFDU$PJOoIUUQPQFOKELKBWBOFUQSPKFDUTDPJO
t 0QFO+%,o+%,'FBUVSFTIUUQPQFOKELKBWBOFUQSPKFDUTKELGFBUVSFT
t $MPTVSFTGPSUIF+BWB1SPHSBNNJOH-BOHVBHFIUUQKBWBDJOGP
t $MPTVSFT 1SPUPUZQF 6QEBUF BOE &YUFOTJPO .FUIPET o IUUQHBGUFSCMPHTQPUDPN
DMPTVSFTQSPUPUZQFVQEBUFBOEFYUFOTJPOIUNM
t &YUFOTJPO.FUIPET1SPQPTBMToIUUQXXXPSFJMMZOFUDPNPOKBWBCMPHFYUFOTJPO@
NFUIPET@QSPQPTBMTIUNM
t /FBM(BGUFSTCMPHIUUQHBGUFSCMPHTQPUDPN
t +BWB1SFEJDUJPOTIUUQKBWBE[POFDPNOFXTKBWBQSFEJDUJPOT
t +BWB4&1SPKFDU+JHTBX.PEVMBSJ[JOH+%,5IF1MBOFUBSJVNIUUQCMPHTTVODPNUIFQMBOFUBSJVNFOUSZQSPKFDU@KJHTBX@NPEVMBSJ[JOH@KEL@
47
Download