Anda di halaman 1dari 53

EMAG | JAVA: PRESENTE E FUTURO

05. Onde foi parar o PermGen do Java?

11. 8 funcionalidades pouco conhecidas do Java 8

15. Anotações de tipos no Java 8: Ferramentas


e oportunidades

22. Java 8: Desmistificando Lambdas

29. Quão funcional é o Java 8?

33. Java 7 - Características que viabilizam o Java 8

36. Q&A: Novidades do Java 8

38. Do Groovy ao Java 8

42. Nashorn: Combinando o poder do Java


e JavaScript no JDK 8

49. Java 9 e além: Brian Goetz e John Rose falam


sobre o futuro do Java

51. Novos Horizontes do Java

2 InfoQ Brasil
CONTEÚDO DETALHADO
Onde foi parar o PermGen do Java? . . . . . . . . . . . . . . . . . . . . . 5 Programação funcional em linguagens não
Adeus PermGen. Olá Metaspace! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 funcionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Mudança para o Metaspace e suas alocações . . . . . . . . . . . . . . . . 6 Java - um pouco de história . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Otimização e Metaspace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 O sistema de tipos original do Java . . . . . . . . . . . . . . . . . . . . . . 30
Questões Atuais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Alternativas a tipos nomeados . . . . . . . . . . . . . . . . . . . . . . . . . . 31
O sistema de tipos do Java 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
8 funcionalidades pouco conhecidas do Java 8 . . 11 Recursos introduzidos no Java 6 e 7 . . . . . . . . . . . . . . . . . . . . . 31
1. StampedLock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 O sistema de tipos do Java 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2. Adicionadores concorrentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Quão funcional é o Java 8? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3. Ordenação Paralela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12
4. Migrando para nova API de data . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Java 7: Características que viabilizam o Java 8 . . . 33
5. Controle de processos do sistema operacional . . . . . . . . . . 13 Operador Diamante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6. Operações numéricas precisas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Manipulador de Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
7. Geração segura de números aleatórios . . . . . . . . . . . . . . . . . . . 13 invokedynamic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
8. Referências opcionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

Anotações de tipos no Java 8: Ferramentas Q&A: Novidades do Java 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . 36


e oportunidades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Sintaxe das anotações de tipo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Do Groovy ao Java 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Detectando erros com anotações . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
O framework Checker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Nashorn: Combinando o poder do Java
Aumentando a produtividade com anotações de tipo . . . . 19 e JavaScript no JDK 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
A estrada à frente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Shell scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Passando dados para o Java e vice-versa . . . . . . . . . . . . . . . . 45
Usando classes Java no Nashorn . . . . . . . . . . . . . . . . . . . . . . . . 45
Java 8: Desmistificando Lambdas . . . . . . . . . . . . . . . . . . . . . . 22 Linguagem funcional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Referência de métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Dialeto especial do JavaScript no Nashorn . . . . . . . . . . . . . . 46
Evolução da biblioteca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Avatar.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Operações de agregação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Resumindo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Fontes de stream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Operações de finalização de Stream . . . . . . . . . . . . . . . . . . . . . . . . . 26 Java 9 e além: Brian Goetz e John Rose falam
Inteface Iterable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 sobre o futuro do Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Novos Horizontes do Java . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Quão funcional é o Java 8? . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Primeiros anúncios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
O que é uma linguagem de programação funcional? . . . . 29 Outras novidades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Data final quase definida, com alguns sacrifícios . . . . . . . . . 52
APRESENTAÇÃO

O
Java 8 é o release atual do Java desde 2014, mas para alguns
ainda é um sonho que o legado não deixa se concretizar. Por
outro lado, ambientes empresariais e grupos de desenvolve-
dores estão se modernizando e gradualmente tornando o novo Java
mainstream. Com o Java 9 planejado para o primeiro semestre de
2017, a versão 8 da linguagem/plataforma mais popular do mundo é
a realidade que queremos conhecer e alcançar hoje. Com essa eMag,
buscamos oferecer uma base para você explorar as muitas novidades
do Java 8 – de novas APIs a mudanças na linguagem. Também vis-
lumbramos um pouco do futuro, concluindo essa coleção de artigos
do InfoQ com um apanhado do que está por vir no Java 9.

O Java 8 contém novas funcionalidades, aprimoramentos e corre-


ções de bugs para maior eficiência no desenvolvimento e na execução;
traz features voltadas ao aumento de produtividade e facilidade de
uso, além de melhorias em programação poliglota, segurança e per-
formance. Se as versões 6 e 7 do Java foram alterações consideradas
leves, o Java 8 está em outro patamar. Mais de 56 novas funciona-
lidades foram adicionadas. Chegaram os lambdas, métodos padrão,
interfaces funcionais e a API de streams, modificando radicalmente
a linguagem e portanto todo o ecossistema Java. Há ainda uma nova
API para datas, novas anotações e aumento de desempenho do engi-
ne para JavaScript.

Neste eMag, o InfoQ leva praticantes numa visita através do Java


8 e as futuras versões da linguagem, explorando como chegamos até
aqui e algumas formas que seguiremos adiante com a tecnologia.

4 InfoQ Brasil
ONDE FOI PARAR O PERMGEN DO JAVA?
por Monica Beckwith, traduzido por Rafael Brito
Com a introdução do JDK8, não existe mais o espaço de PermGen. Os metadados que antes eram armazenados no PermGen não desapareceram,
mas foram movidos para a memória nativa, em uma área conhecida como “Metaspace”. Conheça neste artigo maiores detalhes desta importante
mudança da plataforma Java.

A
Máquina Virtual do Java pela aplicação, elas eram considera- ficassem cheias, ambas as gerações
(JVM) utiliza uma represen- das como “memória não pertencente (permanentes e antigas) seriam cole-
tação interna de suas classes ao heap”. tadas. Um dos problemas mais óbvios
contendo uma série de metadados por Na JVM HotSpot antecessora ao que se pode verificar de imediato é a
classe, tais como: informações de hie- JDK8, a representação “permanente” dependência do -XX:MaxPermSize. Se
rarquia de classes, dados e informa- ficava em uma área chamada per- o tamanho das classes de metadados
ções de métodos (tais como byteco- manent generation (“geração perma- estiver além dos limites do -XX:Max-
des, pilha e tamanho de variáveis), o nente”). A geração permanente era PermSize, sua aplicação será execu-
pool contínuo em tempo de execução, contígua ao heap do Java e limitada a tada com pouco espaço de memória
resoluções de referências simbólicas e -XX:MaxPermSize, que precisava ser e um erro de “Out of Memory” será
Vtables. configurada por linha de comando apresentado.
Anteriormente, quando os class- antes de iniciar a JVM, caso contrá- Curiosidade: Antes do JDK7, para
loaders customizados não eram tão rio seria iniciada com o valor padrão a JVM HotSpot, as Strings internali-
comuns, as classes eram “estáticas” de 64M (85M para 64bit scaled poin- zadas (interned) também eram manti-
em sua maioria, raramente eram des- ters - ponteiros auto-incrementáveis das na geração permanente, também
carregadas ou coletadas, e consequen- com deslocamentos constantes, que conhecida como PermGen, causan-
temente eram marcadas como “per- facilitam o acesso à estrutura). A co- do muitos problemas e erros de Out
manentes”. Além disso, desde que as leção da geração permanente ficaria of Memory. Para mais informações
classes fizessem parte da implemen- associada à coleção da antiga gera- acesse a documentação desse proble-
tação da JVM, e não fossem criadas ção, então sempre que alguma delas ma.

eMag | Java: Presente e Futuro 5


Adeus PermGen. A mudança para o Metaspace foi nhos dos métodos etc.
Olá Metaspace! necessária, pois era realmente difícil Adicionalmente, cada garbage col-
de se fazer o ajuste fino (tunning) do lector na HotSpot precisava de um có-
Com o surgimento do JDK8, Perm- PermGen. Havia ainda a possibilida- digo especializado para lidar com os
Gen não existe mais. As informações de dos metadados serem ser movidos metadados no PermGen. Desacoplar
de metadados não desapareceram, só por qualquer coleta de lixo completa. os metadados do PermGen não só
que o espaço em que eram mantidos Além disso, era difícil dimensionar permite o gerenciamento contínuo do
não é mais contíguo ao heap. Agora, o o PermGen, uma vez que o seu ta- Metaspace, como também melhorias,
metadado foi movido para a memória manho dependia de muitos fatores, tais como: simplificação da coleta de
nativa, em uma área conhecida como tais como: o número total de classes, lixo completa e futura desalocação
“Metaspace”. tamanho dos pools constantes, tama- concorrente de metadados de classe.

Mudança para o Metaspace e formalmente, a área de armazenagem classloader precisa de um segmento,


suas alocações por classloader é chamado de “me- remove-o da lista global e mantém a
Agora a VM Metaspace (Máquina taspace”, e estes metaspaces são co- sua própria lista de segmentos. Quan-
Virtual Metaspace) emprega técnicas letivamente chamados “Metaspace”. do algum classloader é finalizado,
de gerenciamento de memória para A reciclagem ou recuperação de me- seus segmentos são liberados e retor-
gerenciar o Metaspace. Movendo as- taspace por classloader pode ocorrer nam novamente para a lista global de
sim o trabalho de diferentes coletores somente depois que o seu classloader segmentos livres. Esses segmentos
de lixo para uma única VM Metas- não estiver mais ativo e foi relatado são posteriormente divididos em blo-
pace. Uma questão por trás do Me- como inativo pelo coletor de lixo. Não cos e cada bloco contém uma unidade
taspace reside no fato de que o ciclo há realocação ou compactação nestes de metadados. A alocação de blocos
de vida das classes e seus metadados metaspaces, mas os metadados são dos segmentos é linear (ponteiro de
corresponde ao ciclo de vida dos clas- varridos por referências Java. colisão). Os segmentos são alocados
sloaders. Isto é, quanto mais tempo o A VM Metaspace gerencia a alo- fora dos espaços de memória mape-
classloader estiver ativo, mais o meta- cação de Metaspace empregando um ada (mmapped). Há uma lista ligada
dado permanecerá ativo no Metaspa- alocador de segmentos. O tamanho para os tais espaços globais mmapped
ce e não poderá ser liberado. dos segmentos depende do tipo de virtuais, e sempre que algum espaço
Temos usado o termo “Metaspace” classloader. Há uma lista global de virtual é esvaziado, ele é devolvido ao
de forma muito vaga neste texto. Mais segmentos livres. Sempre que um sistema operacional.

6 InfoQ Brasil
A figura acima mostra a alocação então, tecnicamente, o tamanho do leta de lixo. Em tal cenário, recebe-se
de Metaspace com metasegmentos Metaspace poderia assumir o espaço o aviso para configurar o -XX:Metas-
em um espaço virtual mmapped. Os de swap, e começaria a gerar falhas de paceSize para um valor mais elevado
Classloaders 1 e 3 representam a re- alocação nativa. através da linha de comando, para
flexão ou classloaders anônimos e Para uma JVM servidora de 64 bits, evitar as coletas de lixo iniciais.
empregam segmentos de tamanhos o valor padrão/inicial do -XX:Metas- Após coletas subsequentes, a VM
“específicos”. Os Classloaders 2 e 4 paceSize é de 21MB. Esta é a configu- Metaspace será automaticamente
podem ser empregados em segmen- ração do limite máximo inicial. Uma ajustada para o limite mais alto, de
tos de tamanho pequeno ou médio, que vez que esta marca é alcançada, modo a postergar a coleta de lixo do
baseado no número de itens em seus uma varredura de lixo completa é Metaspace.
carregadores. disparada para descarregar classes Há também duas opções: -XX:Min-
(quando os seus classloaders não esti- MetaspaceFreeRatio e -XX:MaxMetas-
Otimização e Metaspace verem mais ativos), e o limite máximo paceFreeRatio, que são análogas aos
Como mencionado anteriormen- é reiniciado. O novo valor deste limite parâmetros do GC FreeRatio e podem
te, uma VM Metaspace gerenciará depende da quantidade de Metaspace ser configurados através da linha de
o crescimento do Metaspace, mas liberado. Se o espaço liberado não for comando.
talvez surgirão cenários em que se suficiente, o limite aumenta; se for li- Algumas ferramentas foram mo-
deseje limitar o crescimento através berado espaço demais, o limite dimi- dificadas para ajudar a obter mais
do uso da configuração explícita do nui. Isto será repetido diversas vezes informações sobre o Metaspace, e são
-XX:MaxMetaspaceSize via linha de se o limite inicial for muito baixo, e listadas a seguir:
comando. Por padrão, o -XX:MaxMe- será possível constatar a repetida co-
taspaceSize não possui um limite, leta de lixo completa nos logs de co-

eMag | Java: Presente e Futuro 7


• jmap -clstats <PID>: exibe as estatísticas de um classloader. (Isto agora assume o lugar do -permstat, que era usado
para exibir estatísticas do classloader de JVMs anteriores ao JDK8). Segue um exemplo de saída no momento de
execução do benchmark da DaCapo Avrora:

$ jmap -clstats <PID>


Attaching to process ID 6476, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.5-b02
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness.liveness analysis may be inaccurate ...
class_loader classes bytes parent_loader alive? type

<bootstrap> 655 1222734 null live <internal>


0x000000074004a6c0 0 0 0x000000074004a708 dead java/util/ResourceBundle$RBClassLoader@0x00000007c0053e20
0x000000074004a760 0 0 null dead sun/misc/Launcher$ExtClassLoader@0x00000007c002d248
0x00000007401189c8 1 1471 0x00000007400752f8 dead sun/reflect/DelegatingClassLoader@0x00000007c0009870
0x000000074004a708 116 316053 0x000000074004a760 dead sun/misc/Launcher$AppClassLoader@0x00000007c0038190
0x00000007400752f8 538 773854 0x000000074004a708 dead org/dacapo/harness/DacapoClassLoader@0x00000007c00638b0
total = 6 1310 2314112 N/A alive=1, dead=5 N/A

• jstat -gc <LVMID>: agora exibe informações do Metaspace, como demonstra o exemplo a seguir:

$jstat-gc <LVMID>
SOC SIC SOU S1U EC EU OC OU MC UM CCSC CCSU YGC YGCT FGC FGCT GCT
1024.0 1024.0 0.0 96.0 6144.0 2456.3 129536.0 2228.3 7296.0 6550.3 896.0 787.0 229 0.211 33 0.347 0.558

Where, MC: Current Metaspace Capacity (KB); UM: Metaspace Utilization (KB)

• jcmd <PID> GC.class_stats: Este é um novo comando de diagnóstico que permite ao usuário final se conectar à
JVM em execução, e obter um histograma detalhado dos metadados das classes Java.

Nota: Com o JDK8 build 13, você deve iniciar o Java com -XX:+UnlockDiagnosticVMOptions.

$ jcmd <PID> help GC.class_stats


9522:
GC.class_stats
Provide statistics about Java class meta data. Requires -XX:+UnlockDiagnosticVMOptions.

Impact: High: Depends on Java heap size and content.

Syntax : GC.class_stats [options] [<columns>]

Arguments:
columns : [optional] Comma-separated list of all the columns to show. If not specified, the following columns are shown:
InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total (STRING, no default value)

Options: (options must be specified using the <key> or <key>=<value> syntax)


-all : [optional] Show all columns (BOOLEAN, false)
-csv : [optional] Print in CSV (comma-separated values) format for spreadsheets (BOOLEAN, false)
-help : [optional] Show meaning of all the columns (BOOLEAN, false)

8 InfoQ Brasil
Um exemplo de saída:

$ jcmd <PID> GC.class_stats

7140:
Index Super InstBytes KlassBytes annotations CpAll MethodCount Bytecodes MethodAll ROAll RWAll Total ClassName
1 -1 426416 480 0 0 0 0 0 24 576 600 [C
2 -1 290136 480 0 0 0 0 0 40 576 616 [Lavro-
ra.arch.legacy.LegacyInstr;
3 -1 269840 480 0 0 0 0 0 24 576 600 [B
4 43 137856 648 0 19248 129 4886 25288 16368 30568 46936 java.lang.Class
5 43 136968 624 0 8760 94 4570 33616 12072 32000 44072 java.lang.String
6 43 75872 560 0 1296 7 149 1400 880 2680 3560 java.
util.HashMap$Node
7 836 57408 608 0 720 3 69 1480 528 2488 3016 avrora.sim.util.
MulticastFSMProbe
8 43 55488 504 0 680 1 31 440 280 1536 1816 avrora.
sim.FiniteStateMachine$State
9 -1 53712 480 0 0 0 0 0 24 576 600 [Ljava.
lang.Object;
10 -1 49424 480 0 0 0 0 0 24 576 600 [I
11 -1 49248 480 0 0 0 0 0 24 576 600 [Lavrora.sim.pla-
tform.ExternalFlash$Page;
12 -1 24400 480 0 0 0 0 0 32 576 608 [Ljava.util.HashMa-
p$Node;
13 394 21408 520 0 600 3 33 1216 432 2080 2512 avrora.sim.AtmelIn-
terpreter$IORegBehavior
14 727 19800 672 0 968 4 71 1240 664 2472 3136 avrora.arch.legacy.
LegacyInstr$MOVW
…<snipped>
…<snipped>
1299 1300 0 608 0 256 1 5 152 104 1024 1128 sun.util.resources.
LocaleNamesBundle
1300 1098 0 608 0 1744 10 290 1808 1176 3208 4384 sun.util.resources.
OpenListResourceBundle
1301 1098 0 616 0 2184 12 395 2200 1480 3800 5280 sun.util.resources.
ParallelListResourceBundle
2244312 794288 2024 2260976 12801 561882 3135144 1906688 4684704 6591392 Total
34.0% 12.1% 0.0% 34.3% - 8.5% 47.6% 28.9% 71.1% 100.0%
Index Super InstBytes KlassBytes annotations CpAll MethodCount Bytecodes MethodAll ROAll RWAll Total ClassName

Questões Atuais
Como mencionado anteriormente, a VM Metaspace emprega um alocador de segmentos. Há múltiplos tamanhos de
segmentos, dependendo do tipo de classloader. Além disso, os itens de classe por si mesmos não possuem um tamanho
fixo, por isso há chances de que os segmentos livres não sejam do mesmo tamanho que os segmentos necessários para os
itens de classe. Tudo isso pode gerar uma fragmentação. A VM Metaspace (ainda) não utiliza compactação, consequente-
mente a fragmentação é uma das principais preocupações neste momento.

eMag | Java: Presente e Futuro 9


Sobre a Autora
Acompanhe Monica no Twitter:
@mon_beck.

Monica Beckwith é uma engenheira de desempenho


trabalhando na indústria de hardware por mais de uma
década. Seu mais atual título é Arquiteta de Desempenho
na Servergy - uma startup que oferece uma nova classe de
servidores Cleantech hiper-eficientes ®. Antes da Servergy,
Monica trabalhou na Oracle / Sun e AMD otimizando a JVM
para sistemas de classe de servidor. Monica foi eleita uma
palestrante “estrela do rock” no JavaOne 2013.

10 InfoQ Brasil
8 FUNCIONALIDADES POUCO
CONHECIDAS DO JAVA 8
por Tal Weiss, traduzido por Vitor Puente
Este artigo visa apresentar algumas das novas APIs do Java 8 que não estão sendo tão comentadas, mas que tornaram o Java melhor de várias
maneiras.

1. StampedLock thread pode causar um deadlock envolvendo ela mesma.


O código multithreaded tem sido um desafio para os O StampedLock possui o modo “otimista”, que emite
desenvolvedores. Com o tempo, algumas construções uma marcação (stamp) retornada por cada operação de
complexas foram adicionadas às bibliotecas Java visando bloqueio (lock). Essa marcação é utilizada como uma es-
auxiliar o desenvolvedor com códigos multithreaded, e pécie de ingresso. Cada operação de desbloqueio (unlo-
seu acesso a recursos compartilhados. Um exemplo é o ck) precisa gerar sua marcação correspondente. Qualquer
ReadWriteLock, que permite ao desenvolvedor dividir o thread que adquirir o bloqueio de escrita, enquanto outra
código em seções que precisam ser mutuamente exclusi- thread está com o bloqueio de escrita do modo otimista,
vas (“writers”) e seções que não precisam (“readers”). fará com que o unlock seja invalidado (o stamp não será
Na teoria parece ótimo. Porém um problema com Re- mais válido). Nesse ponto, a aplicação pode começar tudo
adWriteLock é que a aplicação pode ficar muito lenta, às novamente, possivelmente com um lock no modo “pessi-
vezes até dez vezes mais lenta. O Java 8 introduziu um mista”, que também é implementado pelo StampedLock.
novo bloqueio ReadWrite, chamado StampedLock. A boa O gerenciamento de tudo isso fica por conta do desenvol-
notícia é que o StampedLock é muito rápido. A má notícia vedor. E como um stamp não pode ser utilizado para des-
é que é mais complicado de usar e envolve mais estados. O bloquear outro, deve-se tomar cuidado.
StampedLock não é “reentrante”, o que significa que uma Veja a seguir um exemplo deste tipo de lock em ação:

eMag | Java: Presente e Futuro 11


long stamp = lock.tryOptimisticRead(); //sem caminho bloqueante - muito rápido.
work (); // é esperado que não ocorra nenhuma escrita por hora.
if (lock.validate(stamp)){
//sucesso! Sem contenção com a thread de escrita.
} else {
//outra thread precisa obter um bloqueio de escrita entretanto mudando o stamp.
//voltando a ter um bloqueio de leitura mais pesado.
stamp = lock.readLock(); //Este é uma operação de leitura que causa o lock.
try {
//Sem escrita acontecendo agora.
work();
} finally {
lock.unlock(stamp); // Liberação do stamp utilizado.
}
}

2. Adicionadores concorrentes 3. Ordenação Paralela


Outra novidade do Java 8 lida especificamente Assim como os Adicionadores aceleram os conta-
com código escalável: os “Adicionadores Concorren- dores, o Java 8 traz uma maneira concisa de acelerar a
tes (Concurrent Adders)”. Um dos padrões mais bási- ordenação. E de uma maneira muito simples, em vez
cos de concorrência é a leitura e escrita de contadores de realizar a ordenação desta maneira:
numéricos. Há diversas maneiras de fazer isso hoje Array.sort(myArray);
em dia, mas nenhuma tão eficiente ou elegante como Agora pode utilizar o método pronto para a para-
a existente no Java 8. lelização:
Antes do Java 8, isso era feito utilizando “Atomics”, Arrays.parallelSort(myArray);
que utilizavam instruções diretas da CPU de compa- Isso automaticamente dividirá a sua coleção em
ração e swap (CAS), através da classe sun.misc.Un- partes, as quais serão ordenadas através de um nú-
safe, para realizar a tentativa e marcar o valor de um mero de “cores” e então agrupadas novamente. Há
contador. O problema era que quando um CAS falha- uma ressalva, quando o método de ordenação para-
va devido a uma contenção, o AtomicInteger ficava lela é chamado em ambientes com multi-thread ele-
em loop, tentando continuamente o CAS em um loop vado, tal como um web container sobrecarregado, os
infinito, até o seu sucesso. Em altos níveis de conten- benefícios iniciais são reduzidos, até mais de 90%, de-
ção isso poderia se mostrar muito lento. vido ao aumento de trocas de contexto da CPU.
A partir do Java 8 foi adicionado o LongAdders.
Esse conjunto de classes fornece uma maneira con-
veniente de leitura e escrita de valores numéricos 4. Migrando para nova API de data
em cenários de grande escalabilidade. A utilização é O Java 8 introduz uma nova API de datas. Uma
simples. Basta iniciar um novo LongAdder e utilizar nova maneira de lidar com horas e a maioria dos mé-
os seus métodos add() e intValue() para aumentar e todos da versão atual estão marcados como obsoletos.
retornar o contador. A nova API traz a facilidade de uso e a precisão for-
A diferença entre esta versão do Atomics e a an- necidas pela popular API Joda Time para o núcleo da
tiga é que, quando o CAS falha devido a alguma biblioteca Java.
contenção, em vez de fazer o giro na CPU, o Adder Assim como em qualquer nova API, as boas novas
armazenará o delta em uma célula interna alocada são o estilo mais elegante e funcional. Infelizmente,
para aquela thread. Então adicionará o valor junto de muito já foi feito com a antiga API e a transição deve-
qualquer outro valor de células pendentes ao resul- rá levar tempo.
tado do método intValue(). Isso reduz a necessidade Para ajudar na transição, a classe Date possui um
de voltar e realizar o CAS novamente, ou bloquear novo método chamado “toInstant()”, que converte
outras threads. uma data para a nova representação. Isso é especial-
A utilização do modelo de Adicionadores concor- mente útil ao fazer uso de APIs que recebe o formato
rentes deve ser sempre preferido frente ao modelo clássico de data, pois basta converter a data para o
Atômico para o gerenciamento de contadores. novo formato e utilizar todos os benefícios da nova
API de datas.

12 InfoQ Brasil
5. Controle de processos do sistema recursos que funcionam corretamente em pré-produ-
ção, podem começar a se comportarem de maneira
operacional completamente estranha de repente, quando as ope-
Lançar um processo do sistema operacional di- rações sofrem o overflow e produzem valores ines-
retamente do código Java já é possível através das perados.
chamadas Java Native Interface (JNI), mas com isso é Para auxiliar nesse problema, o Java 8 adicionou
bem provável se deparar com resultados inesperados diversos métodos “exact” à classe Math, protegendo
ou exceções sérias mais para a frente. Ainda assim, é um código suscetível a overflows, através do lança-
um mal necessário. mento de “uncheckedArithmeticException” quando
Além disso, os processos têm mais um lado desa- o valor de uma operação causa um overflow.
gradável – o fato de tenderem a ficar suspensos. O
int safeC = Math.multiplyExact(bigA, bigB);
problema ao iniciar um processo a partir do código
// Será lançada uma ArithmeticException caso o
Java até a versão 7 tem sido difícil o controle sobre um
resultado exceda +-2^31
processo uma vez iniciado.
Para ajudar nessa tarefa o Java 8 traz três novos O único aspecto negativo disso é que a responsa-
métodos na classe “Process”: bilidade em identificar como o código pode ter pro-
1. destroyForcibly() termina um processo com blemas com overflow fica por conta de quem está de-
um grau de sucesso bem maior do que antes; senvolvendo. Não há solução mágica, porém isso já é
2. isAlive() informa se um processo iniciado ainda melhor que nada.
está vivo;
3. Uma nova sobrecarga de waitFor() especifica a
quantidade de tempo para que o processo termine. 7. Geração segura de números aleatórios
Isso retorna ou o sucesso da execução ou o time-out, O Java tem sido criticado por anos pelos proble-
neste último caso é possível terminar o processo. mas de segurança. Justo ou não, um grande esforço
Duas boas utilizações para estes métodos são: tem sido feito para blindar a JVM e os frameworks de
• Caso um processo não termine no tempo deter- possíveis ataques. Os números aleatórios com baixo
minado, forçar seu término e seguir em diante: nível de entropia tornam sistemas que os utilizem na
criação de chaves para criptografia ou códigos hash
if (process.wait(MY_TIMEOUT, TimeUnit.MILLISECONDS)){ mais suscetíveis a ataques.
//success! Até o momento, a escolha do algoritmo de geração
} else { de números aleatórios é de responsabilidade do de-
process.destroyForcibly(); senvolvedor. O problema é que, nas implementações
} que dependem de um hardware, sistema operacional
• Garantir que, antes que um código termine, não ou JVM específicos, o algoritmo desejado pode não
seja deixado nenhum processo para trás. Proces- estar disponível. Em tais casos, as aplicações têm ten-
sos suspensos certamente esgotarão seu sistema dência a migrar para versões mais fracas de gerado-
operacional, mesmo que lentamente. res, o que aumenta o risco de ataques.
O Java 8 adicionou o novo método SecureRandom.
for (Process p : processes) { getInstancStrong() com o objetivo de permitir que a
if (p.isAlive()) { JVM escolha uma versão segura. Se escrever código
p.destroyForcibly(); sem o completo controle sobre o hardware/SO/JVM
} em que será executado, deve-se considerar o uso des-
} te método. (É uma situação comum quando se cons-
troem aplicações a serem executadas na nuvem ou
em ambientes de PaaS.)

6. Operações numéricas precisas


Um overflow numérico pode causar alguns dos 8. Referências opcionais
mais estranhos problemas em software, dada sua As exceções do tipo NullPointerException são bem
característica implícita. Isso é especialmente verda- antigas. Porém ainda hoje estão presentes no dia-a-
de em sistemas que possuem contadores inteiros in- -dia de uma equipe de desenvolvimento, não importa
crementados de acordo com o tempo. Nesses casos, quão experiente a equipe seja. Para ajudar com este

eMag | Java: Presente e Futuro 13


problema o Java 8 introduz um novo template cha- O template Optional possui funções que tornam
mado Optional<T>. o trabalho mais conveniente, como “isPresent()” que
Baseado em linguagens como Scala e Haskell, esse verifica se um valor não-nulo está disponível, ou
template indica explicitamente quando uma referên- “ifPresent()”, que recebe uma função Lambda que
cia passada ou retornada por uma função pode ser será executada caso “isPresent()” seja verdadeiro. O
nula. Isso ajuda a reduzir as dúvidas se uma referên- lado negativo é, assim como ocorre com a nova API
cia pode ou não ser nula, devido à confiança em do- de Data e Hora, levará tempo até que está novidade
cumentações que podem estar desatualizadas, ou a esteja presente nas diversas APIs usadas diariamente.
códigos que podem mudam com o tempo. Aqui está a nova sintaxe Lambda para escrever um
valor opcional:
Optional<User> tryFindUser(int userID) {
ou value.ifPresent(System.out::print);
void processUser(User user, Optional<Cart>
shoppingCart) {

Sobre o Autor

Tal Weiss é o CEO da Takipi. Weiss vem desenhando aplicações escalá-


veis, de tempo real em Java e C++ nos últimos 15 anos. Ele ainda gosta de
analisar um bom bug através da instrumentação de código Java. Em seu
tempo livre Weiss toca Jazz na bateria.

14 InfoQ Brasil
ANOTAÇÕES DE TIPOS NO JAVA 8: FERRAMENTAS
Epor Todd
OPORTUNIDADES
Schiller, traduzido por Wellington Pinheiro
As anotações no Java 8 podem ser escritas não apenas em declarações, mas também em qualquer uso de tipos como nas declarações, generics e
conversões de tipos (cast). Nesse artigo são apresentadas as anotações de tipos e as ferramentas que ajudam a construir aplicações melhores.

N
as versões anteriores do Java era possível anotar no Java 1.5. Em projetos com muitas heranças não triviais,
somente declarações. Com o Java 8 as anotações torna-se difícil rastrear qual implementação de um méto-
podem ser escritas em qualquer local que os ti- do será executado. Nesse contexto, se não forem tomados
pos são usados, como por exemplo: declarações, generics os devidos cuidados ao modificar a assinatura de um mé-
e conversões de tipos (casts), como apresentado no código todo, isso pode fazer com que o método de uma subclasse
a seguir: deixe de ser executado, pois ele deixará de sobrescrever
o método da superclasse recém alterado. Eliminar a cha-
@Encrypted String data; mada de um método dessa forma pode introduzir uma
List<@NonNull String> strings; falha ou alguma vulnerabilidade. Em decorrência disso,
myGraph = (@Immutable Graph) tmpGraph; a anotação @Override foi introduzida. Ela permite que
os desenvolvedores deixem explícito os métodos que so-
À primeira vista, as anotações de tipo não aparentam brescrevem outros métodos da superclasse. O compilador
ser uma das funcionalidades mais atraentes dessa nova Java usa essa informação para advertir o desenvolvedor
versão do Java. Ao contrário, em relação à linguagem em quando o código não reflete essa intenção. Usando essa
si, as anotações possuem somente uma sintaxe e as fer- abordagem, as anotações agem como um mecanismo
ramentas é que dão a sua semântica, isto é, significado e para auxiliar na verificação automática do programa.
comportamento. Além da verificação automática, as anotações têm de-
Como desenvolvedor Java, é provável que as anotações sempenhado um papel central para aumentar a produti-
já estejam sendo utilizadas para melhorar a qualidade do vidade através de técnicas de metaprogramação. A ideia
software. Considere a anotação @Override, introduzida é que as anotações podem informar as ferramentas sobre

eMag | Java: Presente e Futuro 15


como gerar código auxiliar, fazer transformações no tação pode ser aplicada em qualquer ponto que um
código ou definir como o programa deverá se com- tipo é usado, por exemplo em declarações, generics e
portar em tempo de execução. Por exemplo a API de conversões de tipos (casts). O código a seguir exem-
persistência JPA (Java Persistence API), introduzida plifica alguns dos usos desses tipos de anotações:
no Java 1.5, permite que os desenvolvedores especifi-
quem de forma declarativa uma correspondência en- @TypeUse class MyClass<@TypeParameter T extends @TypeUse
tre objetos Java e entidades do banco de dados através Integer> {
de anotações, tal como: @Entity. Ferramentas como o @TypeUse <@TypeParameter S> MyClass(String s) {
Hibernate podem usar essas anotações para fazer ma- ...
peamentos e consultas SQL em tempo de execução. }
No caso do JPA e do Hibernate, as anotações são public static void main(String ... args) {
usadas para evitar a escrita de código repetitivo, re- Object o = ( @TypeUse String ) new String( “Test” );
duzindo assim a duplicidade de código - princípio co- if( o instanceof @TypeUse String ){
nhecido como Não Se Repita (Don’t Repeat Yourself ...
- DRY). Curiosamente, sempre que se olha para as fer- }
ramentas que auxiliam na aplicação de boas práticas, }
não é difícil encontrar o uso de anotações. Alguns }
exemplos notáveis ajudam na redução do acoplamen- Assim como as anotações em declarações, as
to através da Injeção de Dependência e também na anotações de tipos podem ser salvas junto com
separação de responsabilidades com a Programação o arquivo de bytecode gerado e acessadas em
Orientada a Aspectos tempo de execução via reflection através das
Mas se as anotações já estão sendo usadas para políticas de retenção: RetentionPolicy.CLASS ou
melhorar a qualidade do código, por que usar anota- RetentionPolicy.RUNTIME, usadas na definição
ções de tipos? da anotação. Existem duas diferenças fundamentais
Uma resposta simples é que as anotações de ti- entre as anotações de tipo e as suas predecessoras.
pos trazem mais possibilidades. Elas permitem, por Primeiro, as anotações de tipo aplicadas a variáveis
exemplo, que mais tipos de falhas sejam detectados locais podem ser salvas junto com o bytecode.
automaticamente e dão mais controle às ferramentas Segundo, o tipo usado com generics também é salvo
de produtividade. e fica acessível em tempo de execução.
Embora as anotações fiquem disponíveis em tem-
po de execução, elas não afetam a execução do pro-
Sintaxe das anotações de tipo grama. Por exemplo, um desenvolvedor pode de-
As anotações de tipo no Java 8 podem ser escritas clarar duas variáveis do tipo File e uma variável do
em qualquer local em que um tipo é usado, como por tipo Connection no corpo de um método, da seguinte
exemplo: forma:

File file = new File(“aFile”);


@Encrypted String data
@Encrypted File encryptedFile = new File(“anEncryptedFile”);
List<@NonNull String> strings @Open Connection connection = getConnection();
MyGraph = (@Immutable Graph) tmpGraph;
Supondo que a classe Connection tenha um mé-
Criar uma anotação de tipo é muito simples, todo send(File), é possível executar esse método pas-
basta usar o ElementType.TYPE_PARAMETER, sando como parâmetro qualquer uma das duas vari-
ElementType.TYPE_USE ou ambos, na definição do áveis do tipo File:
alvo (target) da anotação.
connection.send(file);
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) connection.send(encryptedFile);
public @interface Encrypted { }
Como era de se esperar, a ausência de efeito em
O ElementType.TYPE_PARAMETER indica que tempo de execução implica que, embora os tipos pos-
a anotação pode ser usada na declaração de tipos, tais sam ser anotados, os métodos não podem ser sobre-
como: classes ou métodos com generics ou ainda jun- carregados com base nas anotações dos tipos.
to de caracteres coringa em declarações de tipos anô-
nimos. O ElementType.TYPE_USE indica que a ano- public class Connection{

16 InfoQ Brasil
void send(@Encrypted File file) { ... } compilado, executado e causará erro durante a execu-
// A tentativa de sobrecarga a seguir resulta em um erro ção. O compilador Java não faz verificações de anota-
de compilação ções definidas pelo usuário. Apesar disso, a platafor-
// void send( File file) { ... } ma Java expõe duas APIs que auxiliam nessa tarefa,
. . . uma para a criação de plugins para o Compilador e
} outra para o processamento de anotações, de forma
A intuição por trás dessa limitação é que o com- que terceiros possam construir seus próprios méto-
pilador não tem conhecimento sobre a relação entre dos de análise.
tipos anotados e não anotados ou entre tipos com di- Nos exemplos anteriores, as anotações tinham a
ferentes anotações. função de qualificar os valores que as variáveis po-
Repare que há uma anotação @Encrypted na va- deriam conter. Porém, podem ser pensadas outras
riável encryptedFile coincidindo com o parâmetro formas de qualificar o tipo File: @Open, @Localized,
file na assinatura do método send, mas perceba que @NonNull, etc; também pode ser pensada na aplica-
não há nada nesse método que corresponda à anota- ção dessas anotações qualificando outros tipos, como
ção @Open na variável connection. Quando é feita a por exemplo: @Encrypted String. Devido ao fato das
chamada connection.send(...), a variável connection é anotações serem independentes do sistema de tipos
conhecida como uma receptora (receiver) do método do Java, os conceitos expressos através delas podem
(o termo receiver é uma analogia clássica à troca de ser reutilizadas de muitas formas.
mensagens entre objetos na teoria de Orientação a Mas como essas anotações poderiam ser automa-
Objetos). O Java 8 introduz uma nova sintaxe para as ticamente verificadas? Intuitivamente, algumas ano-
declarações de métodos de forma que anotações de tações são subtipos de outras anotações e suas apli-
tipos possam ser escritas em um receptor no método. cações podem ser verificadas em relação aos tipos.
Considere a vulnerabilidade ao ataque de Injeção de
void send(@Open Connection this, @Encrypted File file) SQL, causado pela execução de sentenças SQL modi-
ficadas maliciosamente pelo usuário. Pode-se pensar
Observe nesse último exemplo a sintaxe para defi- em um tipo de dados classificado como @MaybeTain-
nir o método send. O primeiro parâmetro na verdade ted, indicando que o dado pode ter sido adulterado,
faz referência á instância receptora, por isso o nome ou @Untainted, indicando que o dado está garantida-
desse parâmetro é “this”. mente livre de adulteração, pois não foi diretamente
Como citado anteriormente, as anotações não afe- informado pelo usuário.
tam a execução do programa. Assim, um método
declarado com a nova sintaxe do parâmetro receptor @MaybeTainted String userInput;
tem o mesmo comportamento àquele utilizando a @Untainted String dbQuery;
sintaxe tradicional. Na prática, o uso da nova sintaxe
só permite que anotações de tipos sejam escritas no
tipo do receptor.
Uma explicação completa da sintaxe de anotações
de tipos, incluindo sintaxe para arrays multi-dimen-
sionais, pode ser encontrada na especificação JSR
(Java Specification Request) 308.

Detectando erros com anotações


Escrever anotações no código serve para enfatizar
erros quando o código tem algum problema: A anotação @MaybeTainted pode ser vista como
um supertipo da anotação @Untainted. Existem vá-
@Closed Connection connection = ...; rias maneiras de pensar nessa relação. Primeiro, o
File file = ...; conjunto de valores que podem ter sido adulterados
… podem ser um superconjunto de valores que sabida-
connection.send(file); // Problema!: fechada e não mente não foram adulterados (um valor que não foi
criptografada! adulterado pode ser um elemento desse superconjun-
to). Dessa forma, a anotação @Untainted fornece uma
Contudo, esse último código de exemplo pode ser garantia maior que @MaybeTainted. Na prática, essa

eMag | Java: Presente e Futuro 17


tipagem poderia funcionar da seguinte forma: Na prática, os padrões e o controle de fluxo sensí-
veis significam que o desenvolvedor raramente terá
userInput = dbQuery; // OK que escrever anotações no corpo dos métodos, pois o
dbQuery = “SELECT FROM * WHERE “ + userInput; // erro de verificador é capaz de inferir e verificar as anotações
tipo! automaticamente. Mantendo a semântica das anota-
ções fora do compilador oficial do Java garante que
Nesse exemplo, a primeira linha não contém ne- ferramentas de terceiros e os próprios desenvolvedo-
nhum problema, pois userInput supõe que o valor res tomem as suas decisões. Isso permite que a veri-
atribuído pode ter sido adulterado, mesmo que esse ficação de erros possa ser personalizada conforme as
não seja o caso. Por outro lado, essa tipagem revela necessidades de cada projeto.
um erro na segunda linha, pois está atribuindo um A habilidade de definir suas próprias anotações
valor que pode ter sido adulterado a uma variável também permite que seja considerada a verificação
que contém essa restrição. de subtipos específicos do domínio de negócio. Por
exemplo, em um sistema financeiro, as taxas de ju-
ros usam frequentemente porcentagens enquanto a
diferença entre taxas utiliza ponto base (1/100 de 1%).
O framework Checker Com um framework de verificação de unidades po-
O Checker é um framework que faz verificações de dem ser definidas as anotações @Percent e @Basis-
anotações em Java. Lançado em 2007, esse framework Point para garantir que não há confusão no uso dos
é um projeto de código aberto encabeçado pelo sub-li- dois tipos:
der da especificação JSR 308, professor Michael Ernst.
O Checker vem com um conjunto padrão de anota- BigDecimal pct = returnsPct(...); // anotado para devolver @Percent
ções e verificadores de falhas, tais como: NullPointe- requiresBps(pct); // erro: requer @BasisPoints
rException, incompatibilidade no uso de unidades de
medidas, vulnerabilidades de segurança, problemas No exemplo apresentado, devido ao fato do Che-
de concorrência, entre outros. Por ser um verificador cker ser sensível ao fluxo de controle, sabe-se que
que utiliza mecanismos formais de verificação de ti- pct é um @Percent BigDecimal quando é feita a cha-
pagem baseado em lógica, ele é capaz de reconhecer mada para requiresBps(pct) com base em dois fatos:
falhas potenciais que verificadores baseados em heu- returnsPct(...) é anotado para devolver um @Percent
rísticas não detectam. O framework usa uma API de BigDecimal e pct não foi novamente atribuído antes
compilador que detecta as falhas durante a compila- de chamar requireBps(...). Frequentemente, desenvol-
ção. Outra característica é que ele é estensível, o pró- vedores usam convenções de nomes para tentar pre-
prio desenvolvedor pode criar rapidamente os seus venir esses tipos de falha. O que o Checker faz é dar
verificadores de anotações para detectar problemas ao desenvolvedor a garantia de que essas falhas não
específicos da aplicação em questão. existam, mesmo que o código mude e evolua.
A meta do Checker é detectar falhas sem que o O Checker já foi executado em milhões de linhas
desenvolvedor tenha que escrever muitas anotações. de código, apontando centenas de falhas, mesmo em
Isso é feito principalmente através de duas funciona- código bem testado. Um dos exemplos mais interes-
lidades apelidadas como: padrões mais inteligente e sante aconteceu ao executá-lo com a biblioteca muito
controle de fluxo sensíveis. Por exemplo, durante o utilizada Google Collections, agora Google Guava,
processo de verificação de falhas por ponteiros nu- que revelou um possível NullPointerException que
los, o verificador assume que os parâmetros de um não tinha sido detectado após vários testes e nem
método não são nulos por padrão. O verificador pode após utilizar ferramentas heurísticas de análise está-
também utilizar condicionais para determinar quan- tica de falhas.
do uma atribuição de nulo é uma expressão válida. Resultados assim foram obtidos sem fazer muitas
alterações no código existente. Na prática, verificar
void nullSafe(Object nonNullByDefault, @Nullable Object
uma propriedade com o Checker requer somente 2
mightBeNull){
nonNullByDefault.hashCode(); // OK, devido ao padrão
ou 3 anotações para uma centena de linhas de código.
mightBeNull.hashCode(); // Falha! Para aqueles que utilizam o Java 6 ou 7, também é
if (mightBeNull != null){ possível usar o Checker para melhorar a qualidade
mightBeBull.hashCode(); // OK, devido ao padrão do código. As anotações podem ser escritas em co-
}
mentários, tal como:
}

18 InfoQ Brasil
/* @NonNull */ String aString Apesar do Checker ser o melhor framework para
fazer verificação de falhas utilizando anotações, ele
Historicamente, a razão disso é que o Checker foi não é o único atualmente. Tanto o Eclipse quanto o
desenvolvido junto com a JSR 308, que teve início em IntelliJ dão suporte a esse tipo de anotação:
2006.

POSSUEM SUPORTE
Checker Framework Suporte completo, incluindo anota-
ções em comentários.
Eclipse Suporte à verificação de valores não
nulos.
IntelliJ IDEA Podem ser escritos inspecionadores
personalizados, suporte à verificação
de valores não nulos.
NÃO POSSUEM SUPORTE
PMD
Coverity
Check Style Sem suporte para Java 8.
Find Bugs Sem suporte para Java 8.

Aumentando a produtividade com anotações de tipo


A ideia inicial por trás das anotações de tipo era a verificação de falhas. Contudo, ainda haviam muitas apli-
cações convincentes desse tipo de anotação em ferramentas de produtividade. Para entender um pouco melhor
o porquê, considere os seguintes exemplos de como as anotações são usadas

Programação Orientada a Aspectos @Aspect, @Pointcut, etc.


Injeção de Dependência @Autowired, @Inject, etc.
Persistência @Entity, @Id, etc.

As anotações são especificações declarativas para executar um aplicativo em tempo de compilação que
informar como as ferramentas devem gerar código adiciona código ao programa com base em um con-
ou arquivos auxiliares e como as ferramentas devem junto de regras. Por exemplo, pode ser definida uma
se comportar durante a execução do programa. O uso regra que automaticamente faz autenticação com
das anotações desse modo pode ser considerado uma base no tipo anotado:
forma de metaprogramação. Alguns frameworks, tal
como o Lombok, tiram vantagem da metaprograma- void showSecrets(@Authenticated User user){
ção com anotações ao extremo, resultando em um có- // Inserido automaticamente pela AOP:
digo que mal parece Java. if (!AuthHelper.EnsureAuth(user)) throw . . .;
Considere a Programação Orientada a Aspectos }
(Aspect Oriented Programming - AOP). A AOP aju- Como antes, a anotação está qualificando o tipo.
da na separação de propriedades ortogonais de uma Ao invés de verificar as anotações em tempo de com-
aplicação, tais como log e autenticação, daquelas rela- pilação, a AOP é usada para fazer a verificação em
cionadas às regras de negócio. Com a AOP é possível tempo de execução automaticamente. Esse último

eMag | Java: Presente e Futuro 19


exemplo mostra a anotação de tipo sendo usada para Um bom exemplo dessa abordagem é o framewok
dar um controle maior sobre como e quando a AOP EnerJ, de Adrian Sampson, para computação com
modifica o programa. eficiência energética utilizando a computação aproxi-
O Java 8 também dá suporte às anotações de tipo mada. EnerJ baseia-se na observação de que em certas
em declarações locais que são persistidas nos arqui- ocasiões, tal como o processamento de imagens em
vos de bytecode. Isso cria novas oportunidades para dispositivos móveis, faz sentido reduzir a precisão
se ter uma AOP mais granular. Por exemplo, para para poupar energia. Um desenvolvedor usando o
incluir código de rastreamento de uma forma mais EnerJ pode anotar um dado que não é crítico usan-
granular: do a anotação @Approx. Com base nessa anotação, o
ambiente de execução do EnerJ usa vários atalhos ao
// Faz o rastreamento de todas as chamadas ao objeto ar manipular esse dado. Por exemplo, pode ser utiliza-
@Trace AuthorizationRequest ar = . . .; do um hardware de cálculos aproximados de baixo
consumo de energia para armazenar e fazer cálculos.
Novamente, as anotações de tipo dão maior con- Contudo, tendo dados aproximados se movendo pelo
trole ao se fazer metraprogramação com AOP. A In- programa pode ser perigoso, e nenhum desenvolve-
jeção de Dependência é uma história similar. Com o dor vai querer controlar o fluxo afetado por esse dado
Spring 4, é finalmente possível usar generics como aproximado. Portanto, o EnerJ usa o Checker para ga-
qualificador: rantir que os dados aproximados não sejam utiliza-
dos em sentenças de controle de fluxo, por exemplo,
@Autowired private Store<Product> s1; em sentenças condicionais como ifs.
@Autowired private Store<Service> s2; Mas as aplicações dessa abordagem não são limi-
tadas a dispositivos móveis. Em finanças, frequen-
Com generics é possível eliminar a necessidade temente há um conflito entre precisão e velocidade.
introduzir classes como ProductStore e ServiceStore Nesses casos, o ambiente de execução pode decidir
ou usar regras mais frágeis de injeção baseada em entre usar um algoritmo de Monte Carlo para o cálcu-
nomes. lo de caminhos, um critério de convergência ou mes-
Com anotações de tipo, não é difícil imaginar que mo processar algo em um hardware especializado
um dia o Spring permita usá-las para controlar a inje- com base nas demandas atuais ou na disponibilidade
ção da seguinte forma: de recursos.
A beleza desse abordagem é que a preocupação de
@Autowired private Store<@Grocery Product> s3; como uma execução deve ser feita fica fora da lógica
de negócio central da aplicação, que descreve o que
Esse exemplo mostra um tipo anotado servindo deve ser feito.
como um mecanismo de separação de interesses, fa-
vorecendo para que a hierarquia de tipos do projeto
seja mais concisa. Essa separação só é possível por-
que as anotações de tipo são independentes do siste-
ma de tipagem do Java.

A estrada à frente
Como apresentado, as anotações de tipo podem
ser usadas tanto para detectar como prevenir erros
em programas e também para aumentar a produti-
vidade. Contudo, o potencial real das anotações de
tipos está em combinar a verificação de erros e a me-
taprogramação para dar suporte aos novos paradig-
mas de desenvolvimento.
A ideia básica é construir ambientes de execução
e bibliotecas que alavanquem a abordagem de criar
programas automaticamente mais eficientes, parale-
los ou seguros e que façam com que os desenvolvedo-
res usem as anotações corretamente.

20 InfoQ Brasil
Conclusão
No Java 8, as anotações podem ser usadas em qualquer tipo, incrementando a capacidade de escrever anota-
ções em declarações. As anotações por sí próprias não afetam o comportamento do programa. Contudo, utili-
zando ferramentas como o Checker, é possível utilizá-las para verificar automaticamente a ausência de falhas e
aumentar a produtividade com metaprogramação. Enquanto ainda levará algum tempo para que as ferramentas
existentes obtenham total vantagem das anotações de tipos, agora é hora de começar a explorar como as anota-
ções de tipos podem melhorar tanto a qualidade do software desenvolvido quanto a produtividade.

Sobre o Autor

Todd Schiller é diretor da FinLingua, uma companhia de consultoria


e desenvolvimento de software para a área financeira. A prática de
consultoria da FinLingua ajuda equipes de desenvolvimento a adotar
uma linguagem específica de domínio, metraprogramação e técnicas
de análise de programas. Todd é um membro ativo da comunidade de
pesquisa em engenharia de software; sua pesquisa em especificação e
verificação tem sido apresentada nas principais conferências interna-
cionais, incluindo ICSE e OOPSLA.

eMag | Java: Presente e Futuro 21


JAVA 8: DESMISTIFICANDO LAMBDAS
por Simon Ritter, traduzido por Rafael Sakurai
O artigo destaca os pontos principais da palestra “Lambdas & Streams” que Simon Ritter apresentou no QCon London 2014. Ele explica o que são as
expressões Lambdas, interface funcional, referência de métodos, Streams, operações de agregação e diversos exemplos

S
e perguntarmos aos desenvolvedores Java sobre o petitivo.
Java 8, teremos diversas respostas bem animadas, Neste problema, queremos encontrar a maior nota em
especialmente sobre o uso das expressões lambda. uma coleção de estudantes. Usamos um idioma comum
Mas após uma conversa mais honesta, encontramos de iteração externa para percorrer e comparar cada ele-
um fervor misturado com um pouco de receio em relação mento da coleção.
às novas e misteriosas APIs disponíveis na Web. Simon Mas há algumas desvantagens no código. Em primeiro
Ritter revelou alguns dos mistérios na apresentação sobre lugar, a iteração externa significa que os desenvolvedores
lambdas na conferência QCon London 2014. são responsáveis pela implementação (programação im-
A seguir, temos um trecho de código Java que ilustra perativa), e como é usado um único loop, definimos que
um padrão comum: a execução do código será de modo sequencial. Se qui-
Nota: As partes em vermelho são aquelas que estamos sermos otimizá-lo, não poderíamos facilmente segmentar
interessados; e as partes em azul representam código re- em um conjunto de execução de instruções em paralelo.
Em segundo lugar, a variável highestScore é mutável
e não é thread-safe. Então, mesmo que quiséssemos que-
brá-lo em múltiplas threads, precisaríamos adicionar um
lock (bloqueio) para prevenir race conditions (condições
de concorrência), que por sua vez podem introduzir pro-
blemas de desempenho.
Agora, se quisermos agir de modo mais inteligente,
podemos mudar um pouco mais a implementação em
direção ao estilo funcional utilizando uma classe interna
anônima:

22 InfoQ Brasil
mado “op”, que simplesmente compara o ano de gra-
duação do estudante com 2011 e retorna o resultado.
Enviaremos o resultado (todos os estudantes gra-
duados em 2011) para o método “map”, que usará ou-
tra classe interna anônima para chamar um método
da interface de mapeamento com seu único método
“extract” para extrair o dado que queremos (chaman-
do o método getScore). Então passaremos esse resul-
tado, que é um conjunto de notas de todos estudantes
graduados em 2011, para o método “max”, que enfim
entregará o maior valor a partir do conjunto de re-
sultados.
Usando essa abordagem, tratamos toda a intera-
ção, filtro e acúmulo com o uso da biblioteca, sem
precisar fazer isso de forma explícita. Isso não somen-
te simplifica a implementação, como também elimina
o compartilhamento de estado, deixando mais fácil
pedir ao código da biblioteca para decompor a imple-
mentação em diversas sub tarefas e alocá-lo em di-
ferentes threads para serem executadas em paralelo.
Nessa implementação, eliminamos o estado mu- Em muitos casos, também executamos uma avaliação
tável e passamos o trabalho da interação para a bi- posterior, economizando ainda mais tempo.
blioteca. Estamos encadeando uma sequência de cha- Então, uma abordagem que usa classe interna
madas de métodos para aplicar a operação em uma anônima é rápida e thread-safe, mas atente-se para
expressão “Olhe para todos os meus estudantes e fil- as cores do código fonte. Note que a quantidade em
tre apenas aqueles que se graduaram em 2011”. azul é maior do que em vermelho, indicando código
A classe interna anônima implementa a interface repetitivo.
Predicate (ela contém um método, aceita um parâme- Então, entram em cena as expressões lambda!
tro e retorna um valor booleano) com o método cha-

Pense nas expressões lambda como um método, 2011.


no sentido de que ele aceita parâmetros, tem corpo e Note que não há um retorno explicito. Simples-
retorna um tipo estático. mente dizemos “Compare o ano de graduação com
Nesse exemplo, usamos as expressões lambda 2011” e o compilador deduz que destina-se a interface
para obter o mesmo algoritmo que determina qual a Predicate (que tem um único método que necessita de
maior nota, como nos exemplos anteriores. Vejamos uma assinatura com um retorno do tipo booleano).
em detalhes. O método map é processado de forma similar, usan-
Primeiro, criamos um Stream a partir de uma Col- do uma expressão lambda, passando um estudante S
lection. O método stream é novo na interface Collec- como parâmetro e mapeando (como um tradutor) seu
tion e funciona de forma parecida com um Iterator valor de retorno, que é a nota (score) do estudante. O
embutido (veremos em mais detalhes logo adiante). método map não deve ser confundido com o java.util.
O stream prepara os resultados da coleção, que en- Map que usa pares de chave-valor. O método map da
tão passa para o método filter, descrevendo “como” classe Stream retorna uma nova instância do Stream
as partes serão filtradas usando a expressão lambda contendo os resultados da operação aplicada para to-
que compara o ano de graduação dos estudantes com dos os elementos da Stream de entrada, produzindo,

eMag | Java: Presente e Futuro 23


nesse caso, um Stream com todas as notas. o compilador identifica pela estrutura. O compilador
Usando lambdas implementamos o mesmo algo- pode determinar a interface funcional representada a
ritmo com muito menos código. É mais compreensí- partir de sua posição. O tipo de uma expressão lamb-
vel, portanto menos propenso a erros, e como visto, da é o da interface funcional associada.
ele pode ser alterado para um algoritmo paralelo uma Como o compilador conhece os locais que são usa-
vez que não há compartilhamento de estado. dos uma expressão lambda, é possível determinar
Como Ritter disse em sua apresentação: muito sobre essa expressão. Portanto como o compi-
lador sabe o tipo da interface funcional, então pode
inferir os outros tipos necessários.
“As expressões Lambda representam uma função
Mas, Ritter avisa:
anônima. Então, elas são como métodos, mas não são
“Um ponto de atenção é que embora não tenhamos
realmente um método. Elas são como funções anô-
explicitamente colocado o tipo da informação lá, isso
nimas no sentido de que elas tem as mesmas funcio-
não significa que está usando uma tipagem dinâmica
nalidades de um m étodo, mas elas não são métodos
no Java. Nunca faríamos isso, é desagradável e ruim.
porque não estão associadas com uma classe. Se pen-
Então, o que fazemos é dizer que isso ainda é uma tipa-
sar no Java como programamos hoje, criamos classes
gem muito estática, mas com menos digitação.”
e classes têm métodos. Portanto o método tem uma
Ainda segundo Ritter, uma coisa que diferencia as
classe associada a ele. No caso das expressões Lambd
expressões lambda dos closures, é que ao contrário
dentro de uma expressão Lambda e ela tem um corpo,
dos closures, as lambdas não podem acessar as vari-
que defini o que ela fará. Também é possível fazer as
áveis que estão fora da expressão lambda, exceto as
mesmas coisas que um método: pode agrupar instru-
variáveis que são efetivamente final, isso significa que
ções; pode usar chaves e ter múltiplas instruções sem
embora a variável não precisa da palavra-chave final
nenhum problema. A coisa mais importante sobre isso
(ao contrário de uma classe interna), no entanto o seu
é que agora permite usar uma maneira simples de ter
valor não pode ser reatribuído.”
um procedimento parametrizado, não apenas valores
parametrizados.”

Ritter ampliou esse conceito apontando que uma Referência de métodos


vez que uma lambda é uma função sem uma classe, A sintaxe da referência de método é outra nova
então a palavra-chave “this” não se refere a própria funcionalidade da expressão lambda. É um atalho
lambda, mas sim a classe na qual foi declarada. Isso que permite reutilizar um método basicamente como
distingue de uma classe interna anônima, na qual uma expressão Lambda. Podemos fazer coisas como:
“this” refere-se a própria classe interna.
É útil olhar para as decisões de implementações FileFilter x = f -> f.canRead();
que os designers da linguagem fizeram para desen-
volver os lambdas. Essa sintaxe diz para o programa criar um FileFil-
Olhando para o Java como um todo, há muitas in- ter que filtra os arquivos com base em uma proprie-
terfaces que possuem apenas um método. dade comum – nesse caso, se o arquivo pode ser lido.
Vamos definir uma interface funcional como uma Note que nesse exemplo, nunca mencionamos que f é
interface com exatamente um método abstrato, por um arquivo; o compilador infere através da assinatu-
exemplo: ra do único método no FileFilter:

interface Comparator<T> { boolean compare(T x, T y); } boolean accept(File pathname);


interface FileFilter { boolean accept(File x); }
Podendo ser simplificado ainda mais usando a
interface Runnable { void run(); }
interface ActionListener { void actionPerformed(…); }
nova notação do Java 8 “::”.
interface Callable<T> { T call(); }
FileFilter x = File::canRead;
Uma expressão Lambda permite definir uma inter-
face funcional (novamente, um método abstrato) que

24 InfoQ Brasil
Essas sintaxes são completamente equivalentes. Operações de agregação
Para chamar um construtor de forma análoga, Operações de negócios frequentemente envolvem
pode ser utilizado a sintaxe “::new”. Por exemplo, se agregações como: encontrar a soma, máximo, ou mé-
tivermos uma interface funcional como: dia de um conjunto de dados, ou grupo de alguma
coisa. Até agora, tais operações são normalmente exe-
interface Factory<T> { cutadas com loops de interação externa, como disse-
T make(); mos, nos restringindo das otimizações e adicionando
} boilerplate ao código fonte.
Então, podemos dizer: As Streams do Java SE 8 tem como objetivo resol-
ver estes problemas. Nas palavras de Ritter:
Factory<List<String>> f = ArrayList<String>::new;
“Um stream é a maneira de abstrair e especificar
Isso é equivalente a: como processar uma agregação. Ele não é uma estru-
tura de dados. Na realidade é uma maneira de tratar os
Factory<List<String>> f = () -> return new ArrayList<String>();
dados, mas define uma nova estrutura de dados, e in-
E agora, quando f.make() é chamada, será retorna- teressantemente pode tanto finito quanto infinito. En-
do um novo ArrayList<String>. tão, é possível criar um stream de, digamos, números
Usando as interfaces funcionais, o compilador
aleatórios e não precisa mais ter um limite. É aqui que,
pode deduzir muitas coisas sobre a tipagem e inten-
ção, como demonstrado nesses exemplos. algumas vezes, as coisas ficam um pouco confusas. Re-
flita sobre a seguinte questão: - Se tenho um stream
infinito, posso continuar processando os dados para
Evolução da biblioteca sempre. Como faço para parar o que estou fazendo
Uma das vantagens das lambdas e expressão de
códigos como dados é que, como visto, as bibliotecas com os dados?”
existentes foram atualizadas para aceitar lambdas
como parâmetros. Isso introduz alguma complexida- A resposta é que potencialmente não será finaliza-
de: como introduzir métodos na interface sem que- do. É possível fazer facilmente um trecho de código
brar as implementações das interfaces que já existem? usando streams que continua para sempre, como se
Para fazer isso, o Java introduz o conceito de mé- fosse um loop “while(true);” infinito. Ele é como um
todos de extensão, também conhecido como defender Stream: se usar um Stream infinito, ele pode nunca
métodos ou métodos default (padrão). terminar. Mas também é possível fazer um Stream
Vamos explicar usando um exemplo. O método parar - digamos, para fornecer um Stream infinito de
stream foi adicionado na interface Collection para números aleatórios, mas com um ponto de parada.
fornecer um suporte básico ao lambda. Para adicio- Assim o Stream vai parar e o programa pode conti-
nar o método stream na interface sem quebrar as im- nuar sua execução.
plementações existentes da Collection de todo mun- O Stream fornece um pipeline (sequência) de da-
do, o Java adicionou o stream como um método da dos com três componentes importantes:
interface, fornecendo uma implementação padrão: 1. Uma fonte de dados;
2. Zero ou mais operações intermediarias, forne-
interface Collection<E> { cendo um pipeline de Streams;
default Stream<E> stream() { 3. Uma operação terminal(final) que pode realizar
return StreamSupport.stream(spliterator()); duas funções: criar um resultado ou um efeito co-
} lateral. (Um efeito colateral significa que talvez não
} consiga retornar um resultado, mas ao invés disso,
Então, agora temos a opção de implementar o mé- consiga imprimir o valor.)
todo stream ou se preferir usar a implementação pa-
drão fornecida pelo Java.

eMag | Java: Presente e Futuro 25


Nesse exemplo, iniciamos com uma Collection de em 1 (IntRange.rangeClosed(1, 10) gera um stre-
“transações” e queremos determinar o preço total de am de 1 a 10);
todas as transações que foram realizadas por com- »» Files.walk() passando um caminho e algum
pradores de Londres. Obtemos um stream a partir da parâmetro de controle opcional que retorna um
Collection de transações. stream de arquivos individuais ou subdiretó-
Depois obtemos um stream a partir da Collection rios;
de transações. Então, aplicamos uma operação de fil- »» Implementar a interface java.util.Spliterator
tro para produzir um novo Stream com os comprado- para definir sua própria maneira de criar um
res de Londres. Stream. Para mais informações sobre o Splite-
A seguir, aplicamos a operação intermediaria rator consulte o Javadoc do SE 8 fornecido pela
mapToInt para extrair os preços. E finalmente, aplica- Oracle.
mos a operação final de soma para obter o resultado.
Do ponto de vista da execução, o que aconteceu
aqui é que o filtro e o método de map (a operação
Operações de finalização de Stream
intermediaria) não realizaram um trabalho compu- Depois de encadearmos todos esses streams, po-
tacional. Foram apenas responsáveis por configurar demos especificar uma operação de finalização para
o conjunto das operações, e a computação real é exe- executar as pipeline e todas as operações (sequencial-
cutada posteriormente, postergado até chamar a ope- mente ou em paralelo) e produzir os resultados finais
ração final – nesse caso a soma (sum) – que faz todo (ou efeitos colaterais).
trabalho acontecer. int sum = transactions.stream().
filter(t -> t.getBuyer().getCity().equals(“London”)). //Lazy
mapToInt(Transaction::getPrice). //Lazy
Fontes de stream sum(); //Executa o pipeline
Há diversas formas de obter um Stream. Muitos
métodos estão sendo adicionados a API de Collection
(usando a extensão de métodos nas interfaces).
Inteface Iterable
Através de uma List, Set, ou Map.Entry é possível Essa é uma velha conhecida dos dias do Java 1.5, ex-
chamar um método de Stream que retorna uma Stre- ceto que agora tem um método forEach() que aceita
am com o conteúdo da coleção. um Consumer, que aceita um simples argumento e
Um exemplo é o método stream(), ou parallelStre- não retorna valor e produz um efeito colateral. Mas
am(), que internamente a biblioteca usa o framework continua sendo uma interação externa e a melhor for-
de fork/join para decompor as ações em diversas sub- ma de obter um lambda é o método map().
tarefas.
Há outras maneiras de obter um stream:
• Fornecer um array para o método stream() da
classe Arrays;
• Chamar o método Stream.of(), um método está-
tico da classe Stream;
• Chamar um dos novos métodos estáticos para Exemplos:
retornar um stream em particular, por exemplo: Ritter conclui a apresentação com alguns exemplos
»» IntStream.range(), fornecendo um índice de uteis, que estão listados a seguir com comentários ex-
inicio e fim. Por exemplo, IntStream.range(1, 10) plicativos. (As linhas em negrito indicam o especial
gera um stream de 1 a 9 com incremento de 1 uso demonstrado em cada exemplo).

26 InfoQ Brasil
Exemplo 1. Converter palavras para maiúsculo: mapToInt(String::length).
List<String> output = wordList.stream(). // cria um novo stream com o tamanho das strings mapeando
// Mapa de toda a lista de String em maiúsculo. // a atual String ao tamanho correspondente.
map(String::toUpperCase). max().
// Converte o stream para uma lista. // Coleta o maior elemento do stream de tamanho (como
collect(Collectors.toList()); uma optionalInt)
getAsInt();
Exemplo 2. Procurar as palavras // Atualiza o OptionalInt com um int.
com tamanho par na lista:
List<String> output = wordList. Exemplo 6. Coleção de todas as palavras do arquivo
stream(). em uma lista:
//Seleciona somente as palavras com tamanho par. List<String> output = reader.
filter(w -> (w.length() & 1 == 0). lines().
collect(Collectors.toList()); flatMap(line -> Stream.of(line.split(REGEXP))).
// Recebe um stream de palavras de
Exemplo 3. Contar as linhas de um arquivo: // todas as linhas.
long count = bufferedReader. filter(word -> word.length() > 0).
// Recebe um stream com linhas individuais. // Filtra as Strings vazias.
Esse é o novo método do collect(Collectors.toList());
// bufferedReader que retorna um stream<string>. // Cria a lista de retorno.
lines().
// Conta os elementos do stream de entrada. Exemplo 7. Retorna a lista de palavras
count(); minúscula em ordem alfabética:
List<String> output = reader.lines().
Exemplo 4. Juntar as linhas 3 e 4 em uma única String: flatMap(line -> Stream.of(line.split(REGEXP))).
String output = bufferedReader. filter(word -> word.length() > 0).
lines(). map(String::toLowerCase).
// Pula as duas primeiras linhas. // Atualiza o Stream da fonte com o Stream de
skip(2). // letras minúsculas.
// limita a stream a apenas as próximas duas linhas. sorted().
limit(2). // Atualiza o stream com a versão ordenada.
// Concatena as linhas. collect(Collectors.toList());
collect(Collectors.joining()); // Cria e retorna uma Lista

Exemplo 5. Encotrar o tamanho da linha mais longa


em um arquivo:
int longest = reader.lines().

eMag | Java: Presente e Futuro 27


Conclusão
Simon Ritter conclui a apresentação declarando:

“O Java precisa das expressões lambda para facilitar a vida do desenvolvedor. As expressões lambdas eram ne-
cessárias para a criação dos Streams e também para implementar a ideia de passagem de comportamento como a
passagem de valor. Também precisávamos ampliar as interfaces existentes, com o uso das extensões de métodos do
Java SE 8, e que resolve o problema da retro compatibilidade. Isso permite fornecer a ideia de operações em lote na
Collections e permite fazer coisas que são mais simples, e de um modo mais legível. O Java SE 8 está basicamente
evoluindo a linguagem; evoluindo as bibliotecas de classes e também as maquinas virtuais ao mesmo tempo.”

O Java 8 está disponível para download e há um bom suporte a lambda em todos as principais IDEs. Sugiro
que todos os desenvolvedores Java façam o download e usem o Projeto Lambda.

Sobre o Autor

Simon Ritter é o diretor do Evangelismo da tecnologia Java na


Oracle Corporation. Ritter trabalha com negócios de TI desde 1984
e é bacharel de Ciência graduado em Física pela universidade de
Brunel no Reino Unido.

28 InfoQ Brasil
QUÃO FUNCIONAL É O JAVA 8?
por Ben Evans, traduzido por Roberto Pepato
Tem sido falado que o Java 8 trouxe a Programação Funcional para o Java. Neste artigo, Ben Evans discute o que significa ser funcional. Olhando
a evolução do Java — em particular o seu sistema de tipos, é possível ver como os novos recursos do Java 8, especialmente as expressões lambda,
mudam o panorama e fornecem alguns benefícios fundamentais para o estilo de programação funcional.

T
em-se falado muito sobre como O que é uma linguagem de ritmos como estruturas mais funda-
“o Java 8 trouxe a Programação programação funcional? mentais que os dados que operam.
Funcional para o Java” - mas, o Algumas destas linguagens buscam
que isso realmente quer dizer? Em sua essência, uma linguagem desmembrar o estado do programa de
Neste artigo, será apresentado o de programação funcional é aquela suas funções (de uma forma que pare-
que significa ser funcional para uma que trata da mesma forma tanto o có- ce contrária ao desejo das linguagens
linguagem, ou para um estilo de digo como os dados. Isto significa que orientadas a objetos, que normalmen-
programação. Olhando a evolução uma função deve ser um valor de pri- te buscam manter algoritmos e dados
de Java, em particular o seu sistema meira classe na linguagem e deve po- integrados).
de tipos (type system), é possível ver der ser atribuída a variáveis, passada Um exemplo seria a linguagem de
como os novos recursos do Java 8, como parâmetro para funções, entre programação Clojure. Apesar de exe-
especialmente as expressões lamb- outras funcionalidades. cutar sobre a Java Virtual Machine,
da, mudam este cenário e oferecem De fato, muitas linguagens funcio- que é baseada em classes, a Clojure é
alguns dos principais benefícios da nais vão ainda mais longe que isso fundamentalmente uma linguagem
programação funcional. e enxergam a computação e os algo- funcional e não expõe diretamente as

eMag | Java: Presente e Futuro 29


classes e objetos na linguagem de alto utilização de estruturas de dados mu- em algumas formas que a linguagem
nível (embora exista uma boa intero- táveis. assumiu ao longo dos anos:
perabilidade com Java). No entanto, existem outras lingua-
Uma função Clojure, como a fun- gens onde é comum escrever progra-
ção de processamento de log apre- mas no estilo funcional, apesar da O sistema de tipos original
sentada a seguir, é um cidadão de linguagem não impor esta restrição. do Java
primeira classe na linguagem e não Um exemplo seria o Scala, que é uma O sistema de tipos original do Java
precisa ser declarada em uma classe mistura de linguagens orientadas a já possui mais de 15 anos. É simples e
para existir. objetos e funcional e permite utilizar claro, pois os tipos são de referência
funções como valores, tais como: ou primitivos. Os tipos de referências
(defn build-map-http-entries [log-file] (Reference Types) são classes, interfa-
(group-by :uri val sqFn = (x: Int) => x * x ces ou arrays (vetores).
(scan-log-for-http-entries log-file))) ● As classes são a essência da pla-
Mantendo a sintaxe de classes e taforma Java — uma classe é a uni-
A programação funcional é útil objetos que é muito próximas do Java. dade básica de funcionalidade que a
quando os programas são escritos em No outro extremo, é possível es- plataforma Java vai carregar ou refe-
termos de funções que sempre retor- crever programas utilizando progra- renciar — e todo o código destinado
nam a mesma saída para uma entrada mação funcional em linguagens com- para execução deve residir em uma
específica (independente de qualquer pletamente não-funcionais, como é o classe;
outro estado presente no programa caso do C, desde que a disciplina de ● As interfaces não podem ser di-
em execução) e que não causem efei- programação adequada e as conven- retamente instanciadas, ao invés dis-
tos colaterais ou alterem quaisquer ções sejam mantidas. so, uma classe que implementa a API
estados do sistema. Funções que obe- Com isto em mente, a programação definida pela interface deve ser cons-
decem a esta restrição as vezes são funcional deve ser vista como uma truída;
chamadas de funções “puras” e se função de dois fatores — um que é ● Os arrays podem armazenar tan-
comportam da mesma forma que as relevante para as linguagens de pro- to tipos primitivos como instâncias de
funções matemáticas. gramação e outro que é relevante para classes, ou outros arrays;
A grande vantagem das funções programas escritos nesta linguagem: ● Todos os tipos primitivos são
puras é que são mais fáceis de enten- 1) Até que ponto a linguagem de definidos pela plataforma e o progra-
der, pois seu funcionamento não de- programação utilizada auxilia ou re- mador não pode definir novos tipos
pende de estado externo. As funções força a programação funcional? primitivos.
podem ser facilmente combinadas 2) Como este programa específico Desde seus primeiros dias, o sis-
entre si — e isto pode ser observado faz uso das características funcionais tema de tipos do Java vem insistindo
em estilos de fluxos de trabalho dos fornecidas pela linguagem? Ele evita em um ponto muito importante, o de
desenvolvedores como no estilo Ler, utilizar recursos não-funcionais, tais que cada tipo deve possuir um nome
Executar, Imprimir e Laço (Read, Exe- como estado mutável? pelo qual possa ser referenciado. Esta
cute, Print, Loop - REPL), comum a idéia é conhecida como tipagem no-
dialetos Lisp e outras linguagens com minativa (nominative typing) e o Java
forte herança funcional. Java - um pouco de história é uma linguagem com forte tipagem
Java é uma linguagem com perso- nominativa.
nalidade, otimizada para facilitar a Mesmo as chamadas “classes anô-
Programação funcional em
legibilidade, a acessibilidade aos pro- nimas internas (anonymous inner
linguagens não funcionais gramadores iniciantes e para promo- classes)” possuem um tipo pelo qual
A característica de uma lingua- ver o suporte e a estabilidade a longo o programador deve referenciá-las —
gem ser ou não funcional não é uma prazo. Estas decisões de design têm o tipo da interface que implementam:
condição binária — ao invés disto, as um custo, como exemplo a verbosida-
linguagens existem em um espectro. de e no sistema de tipos que pode as Runnable r = new Runnable()
Em um dos extremos desta espectro vezes parecer inflexível quando com- { public void run()
estão as linguagens que basicamente parado a outras linguagens. { System.out.println(“Hello World!”); } };\
forçam a programação funcional, fre- No entanto, o sistema de tipos de
quentemente proibindo estruturas de Java evoluiu, ainda que de forma rela- Outra forma de se dizer isto é a de
dados mutáveis. Clojure é um exem- tivamente lenta, ao longo da história que cada valor no Java é um tipo primi-
plo de linguagem que não permite a da linguagem. Vamos dar uma olhada tivo ou a instância de alguma classe.

30 InfoQ Brasil
um método. Em contraste, o Java não que exigem tratamento especial pelo
Alternativas a tipos nomeados possui esta categoria de tipagem (des- compilador e que são efetivamente
Outras linguagens não têm esse considerando alguns casos extremos separados das hierarquias de tipos
fascínio por tipos nomeados. O Java e bizarros). existentes.
não tem um conceito equivalente ao Os tipos genéricos adicionam uma
do Scala de um tipo que implementa complexidade significativa ao sistema
um método específico (de uma assina- O sistema de tipos do Java 5 de tipos do Java — muito em razão do
tura específica). No Scala, isto poderia O lançamento do Java 5 trouxe três fato de serem um recurso puramente
ser escrito da seguinte forma: principais novos recursos ao sistema de tempo de compilação. Isto exige
de tipos - tipos enumerados (enums), que o desenvolvedor Java esteja aten-
x : {def bar : String} anotações (annotations) e tipos genéri- to aos sistemas de tipo em tempo de
cos (generic types). compilação e em tempo de execução,
Lembre-se que no Scala indica-se o ● Os tipos enumerados (enums) que são ligeiramente diferentes entre
tipo da variável à direita (após o : ), são similares a classes em alguns as- si.
então, isto é lido como: “x é de um tipo pectos, mas eles têm a propriedade Apesar dessas mudanças, a insis-
que possui um método chamado bar de restringir o número de instâncias tência do Java em tipos nominativos
que retorna uma String”. Podemos existentes, e cada instância é distinta permaneceu. Os nomes de tipo ago-
utilizar esta informação para definir e especificada na descrição da classe. ra incluem List<String> (lido como:
um método no Scala da seguinte for- Planejado originalmente para utili- “Lista de String”) e Map<Class<?>,
ma: zação como constante de tipo seguro CachedObject> (“Map de Classe de
(typesafe constant), ao invés da prá- Tipo Desconhecido para CachedOb-
def showRefine(x : {def bar : String}) tica então comum de usar números ject”), mas estes ainda são tipos no-
= { print(x.bar) } inteiros para constantes, a construção meados, e cada valor não primitivo
enum também permite padrões adi- ainda é uma instância de uma classe.
e então, é possível definir um objeto cionais que são, por vezes, extrema-
Scala desta forma: mente úteis;
● As anotações (annotations) estão
Recursos introduzidos
object barBell { def bar = “Bell” } relacionadas a interfaces — a palavra no Java 6 e 7
reservada para declarar uma é @inter- O Java 6 foi essencialmente uma
e ao chamar o método face — com o @ inicial indicando que versão para melhoria de desempenho
showRefine(barBell), o esperado será: este é um tipo de anotação. Como o e de bibliotecas. As únicas mudanças
nome sugere, elas são utilizadas para para o sistema de tipos foi a expansão
showRefine(barBell) Bell anotar elementos de código Java com do papel das anotações e o lançamen-
informações adicionais que não afe- to da capacidade de processamento
Este é um exemplo de tipagem por tam seu comportamento. Anterior- de anotação conectável (pluggable).
refinamento. Os programadores que mente, o Java utilizava o conceito de Isto não impactou a maioria dos de-
vêm de linguagens dinâmicas podem “interfaces de marcação” para forne- senvolvedores Java e não disponibili-
estar familiarizados com o conceito cer uma forma limitada deste tipo de zou um sistema de tipos conectáveis
de duck typing (“se ele anda como um metadado, mas as anotações são con- (pluggable type system) no Java 6.
pato e grasna como um pato, então é sideravelmente mais flexíveis; O Java 7 não mudou materialmente
um pato”). Tipagem por refinamen- ● Os tipos genéricos (generic o sistema de tipos. Os únicos novos
to estrutural (Structural refinement types) do Java fornecem tipos para- recursos, todos de baixa relevância,
typing) é um conceito similar, exceto metrizados - a ideia de que um tipo são:
que duck typing trata de tipos em tem- pode funcionar como um “recipiente” ● Pequenas melhorias na inferên-
po de execução, enquanto os tipos de para objetos de outro tipo, sem levar cia de tipos do compilador javac;
refinamento estrutural funcionam em em conta as especificidades de exa- ● Tratamento de assinatura po-
tempo de compilação. tamente qual é o tipo que está sendo limórfica - utilizado como um detalhe
Em linguagens que possuem a ti- contido. O tipo que se encaixa no reci- de implementação para o recurso cha-
pagem por refinamento estrutural de piente é frequentemente chamado de mado method handles - que, por sua
forma completa, estes tipos refinados tipo de parâmetro (parameter type). vez, foi utilizado para implementar
podem ser utilizados em qualquer Dos recursos introduzidos no Java expressões lambda no Java 8;
lugar que o programador possa es- 5, os enums e as anotações oferecem ● O Multi-catch fornece algumas
perar - como o tipo de parâmetro de novas formas de tipos de referência caracterísitcas de “tipos de dados al-

eMag | Java: Presente e Futuro 31


gébricos (algebraic data types)” - mas A lambda expression do lado di- como tipos (e sua localização no pa-
são puramente internos ao javac e não reito é um valor perfeitamente válido cote utilitário, ao invés do core da
apresentam nenhuma consequência no Java 8 - mas seu tipo é inferido do linguagem) demonstra o estrangu-
real para o programador usuário fi- valor à esquerda - portanto, ela é na lamento que a tipagem nominativa
nal. verdade um valor do tipo Runnable. impõe à linguagem Java e o quão dis-
Entretanto, note que se uma expres- tante a linguagem está da pureza de
são lamdba for utilizada de forma dialetos Lisp ou de outras linguagens
O sistema de tipos do Java 8 incorreta, ocorrerá um erro de compi- funcionais.
Ao longo de sua história o Java foi lação. A tipagem nominativa ainda é a Apesar de tudo o que foi exposto
essencialmente definido por seu siste- forma utilizada pelo Java e até mesmo até aqui, este pequeno subconjunto
ma de tipos. Ele é fundamental para a a introdução de lambdas não mudou do poder das linguagens funcionais
linguagem e tem mantido estrita ade- isso. pode muito bem ser tudo que a maio-
rência aos tipos nominativos. De um ria dos desenvolvedores realmente
ponto de vista prático, o sistema de precisa para suas atividades diárias
tipos do Java não mudou muito entre Quão funcional é o Java 8? de desenvolvimento. Para usuários
o Java 5 e Java 7. Finalmente, vamos voltar para avançados, outras linguagens (na
A primeira vista, poderíamos es- questão que fizemos no início do ar- JVM e em outros lugares) ainda exis-
perar que o Java 8 mudasse isso. Afi- tigo — “Quão funcional é o Java 8?” tem e, sem dúvida, continuam a pros-
nal de contas, uma expressão lambda Antes do Java 8, se o desenvolvedor perar.
parece nos afastar da tipagem nomi- quisesse escrever no estilo funcional,
nativa: seria necessário utilizar tipos ani-
nhados (geralmente classes internas
() -> { System.out.println anônimas) como um substituto para
(“Hello World!”); } literais de funções (function literals).
As coleções de bibliotecas padrão não
Este é um método, sem um nome, ajudariam muito o código e a maldi-
que não recebe parâmetros e retorna ção da mutabilidade estaria sempre
void. Ainda é perfeitamente tipado de presente.
forma estática, mas agora é anônimo. As expressões lambda do Java 8
Será que escapamos do Reino dos não transformam de forma mágica o
Substantivos? Isto é realmente uma Java em uma linguagem funcional.
nova forma de tipos para o Java? Em vez disso, seu efeito é o de criar
A resposta é, talvez infelizmente, uma linguagem ainda imperativa,
não. A JVM, na qual o Java e outras com sistema de tipos ainda nomina-
linguagens executam, é estritamente tivos e que possui um maior suporte
associada ao conceito de classes. O às expressões lambda como literais
carregamento de classes (classloa- de funções. Simultaneamente, as me-
ding) é fundamental para os modos lhorias para as coleções de bibliotecas
de segurança e verificação da plata- permitiram que os desenvolvedores
forma Java. Simplificando, seria mui- Java começassem a adotar expressões
to, muito difícil conceber um tipo que funcionais simples (como filter e map)
não fosse, de alguma forma, represen- para tratar código que seria de alta
tado através de uma classe. complexidade sem estes recursos.
Ao invés de criar uma nova cate- O Java 8 demandou a introdução
goria de tipos, as expressões lambda de alguns novos tipos para represen-
do Java 8 são automaticamente con- tar os blocos de construção básicos de
vertidas pelo compilador para uma fluxos de execução (pipelines) fun-
instância de uma classe. A classe em cionais — interfaces como Predicate,
questão é determinada por inferência Function e Consumer no pacote java.
de tipos. Por exemplo: util.function. Estas adições tornaram
o Java 8 capaz de permitir “programa-
Runnable r = () -> { System.out.println ção ligeiramente funcional” — mas
(“Hello World!”); }; sua necessidade de representá-los

32 InfoQ Brasil
JAVA 7 - CARACTERÍSTICAS QUE
VIABILIZAM O JAVA 8
por Ben Evans, traduzido por Diogo Carleto
Neste artigo, Ben Evans explora algumas funcionalidades do Java 7 que preparam o terreno para os novos recursos do Java 8.

É
uma verdade da indústria de Operador Diamante Na verdade, linguagens como Sca-
tecnologia que os desenvolve- O Java é muitas vezes criticado por la fazem uma grande quantidade de
dores não podem ser mais feli- ser excessivamente verboso. Uma das inferência de tipos a partir de expres-
zes do que quando há cerveja ou uma áreas mais comuns desta queixa está sões e, de fato, declarações de atribui-
oportunidade de reclamar sobre algo na atribuição. No Java 6, somos força- ção podem ser escritas tão simples
oferecido. dos a escrever declarações de atribui- quanto isso:
Então, mesmo após os esforços de ção como esta:
Mark Reinhold e a equipe Java para val m = Map(“x” ->
envolver a comunidade no roadmap Map<String, String> 24, “y” -> 25, “z” -> 26);
após a aquisição da Oracle (a decisão m = new HashMap<String, String>();
Plano A / Plano B), muitos desenvol- A palavra-chave val indica que
vedores Java sentiram que o Java 7 Esta declaração possui muita in- a variável não pode ser reatribuída
“não era bem um release”. formação redundante - devemos ser (como a palavra-chave final para va-
Neste artigo, tentamos refutar essa capazes, de alguma forma, de fazer o riáveis Java). Nenhum tipo de infor-
tese, explorando as funcionalidades compilador entender mais sobre isso mação é especificado sobre a variável,
do Java 7 que preparam o terreno para sozinho, e não exigir que o programa- ao invés disso o compilador Scala exa-
as novas funcionalidades do Java 8. dor seja tão explícito. mina o lado direito da declaração de

eMag | Java: Presente e Futuro 33


atribuição e determina o tipo correto escolhemos essa sintaxe por ser muito maioria dos desenvolvedores Java.
para a variável observando que valor similar ao equivalente em Scala e per- Um manipulador de método é uma
está sendo atribuído. mitir que os desenvolvedores vejam referência tipada de um método para
No Java 7, foram introduzidos al- as similaridades mais facilmente. execução. Podem ser considerados
guns recursos de tipo de inferência li- Ao especificar explicitamente o como “ponteiros para função segura”
mitados, e declarações de atribuições tipo de fn como uma Function que re- (para desenvolvedores familiarizados
podem agora ser escritas da seguinte cebe um argumento Integer e retorna com o C/C++) ou como “A base do Re-
forma: outro Integer, o compilador Java tem flection reimaginado pelos desenvol-
condições de inferir o tipo do parâme- vedores modernos Java”.
Map<String, String> m = new HashMap<>(); tro x como Integer. Este é o mesmo pa- Os manipuladores de métodos de-
drão que vimos na sintaxe diamante sempenham um papel enorme na im-
As principais diferenças entre essa no Java 7 - especificamos os tipos de plementação de expressões lambda.
forma e a do Scala, é que no Scala os variáveis e inferimos o tipo de valo- Protótipos anteriores do Java 8 tinham
valores têm tipos explícitos e esses res. cada expressão lambda convertidas
são os tipos de variáveis inferidos. No Vamos olhar a expressão lambda em uma classe interna anônima em
Java 7, o tipos das variáveis são explí- correspondente no Scala: tempo de compilação.
citos e o tipo de informação sobre es- Vamos começar lembrando que a
ses valores é que é inferido. val fn = (x : Int) => x + 2; expressão (ao menos no Java) lambda é
Alguns desenvolvedores se quei- composta por uma assinatura de fun-
xaram de que eles prefeririam a so- Aqui temos que especificar explici- ção (que na API de manipuladores de
lução Scala, mas acaba por ser menos tamente o tipo do parâmetro x. Como método será representado pelo objeto
conveniente no contexto de uma das não temos o tipo preciso de fn, então MethodType) e um corpo, mas não ne-
principais características do Java 8 - não temos nada para inferir. A forma cessariamente um nome de função.
expressões lambda. de ler no Scala não é extremamente Isto sugere que poderíamos con-
No Java 8, podemos escrever uma difícil, mas a forma do Java 8 tem uma verter a expressão lambda em um
função que adiciona 2 a um inteiro certa clareza na sintaxe que lembra a método sintético que tem a assinatura
dessa maneira: sintaxe diamante do Java 7. correta e que contém o corpo do lamb-
da. Por exemplo a função:
Function<Integer, Integer> fn = x -> x + 2;
Manipulador de Métodos Function<Integer, Integer> fn = x -> x + 2;
A interface Function é nova no Java Os manipuladores de métodos são
8 e está no pacote java.util.function, simultaneamente o novo recurso mais é convertido pelo compilador do Java 8
juntamente com formas especializa- importante do Java 7 e o que é menos no método privado com esse bytecode:
das para tipos primitivos. Entretanto, provável de ser usado no dia-a-dia da

private static java.lang.Integer lambda$0(java.lang.Integer);


descriptor: (Ljava/lang/Integer;)Ljava/lang/Integer;
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokevirtual #13 // Método java/lang/Integer.intValue:()I
4: iconst_2
5: iadd
6: invokestatic #8 // Método java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
9: areturn

Esse método tem a assinatura e expressão lambda, precisamos de um um objeto com o tipo apropriado,
semântica correta (recebe um Integer manipulador de método referencian- como veremos na próxima funciona-
e retorna um Integer). Para usar essa do-a, que será usado para construir lidade que iremos discutir.

34 InfoQ Brasil
Esse método inicial retorna um objeto declaração como:
invokedynamic CallSite, que contém outro manipula-
A última funcionalidade do Java 7 dor de método, que é o alvo atual da Function<Integer, Integer> fn = x -> x + 2;
que abre as portas para o Java 8 é ain- chamada do invokedynamic.
da mais esotérica que os manipulado- 1) A chamada do invokedynamic é é convertida para uma chamada in-
res de método. Esse é o novo bytecode encontrada no fluxo de execução (ini- vokedynamic assim:
invokedynamic - o primeiro bytecode cialmente desvinculado); 2) Chama
a ser adicionado à plataforma desde o o método inicial e retorna um objeto Code:
Java 1.0. Esta funcionalidade é quase CallSite; 3) O objeto CallSite tem um stack=4, locals=2, args_size=1
impossível de ser usada por desen- manipulador de método (o alvo); 4) In- 0: invokedynamic #2, 0 // InvokeDynamic
volvedores na versão 7, porque nessa voca o método manipulador alvo. #0:apply:()Ljava/util/function/Function;
versão o javac não irá, sob nenhuma O método inicial é a maneira na 5: astore_1t
circunstância, gerar um arquivo class qual o código do usuário escolhe qual
que contenha isso. método precisa ser chamado. Para ex- O método de inicialização do in-
Em vez disso, o bytecode foi pro- pressões lambda, a plataforma utiliza vokedynamic é o método estático
jetado ser usado por desenvolvedores um método de inicialização fornecido LambdaMetafactory.metafactory(),
de outras linguagens além do Java, tal pela biblioteca, chamado de lambda que retorna um objeto CallSite ligado
como JRuby, que requer muito mais meta-factory. ao manipulador de método alvo, que
execução dinâmica que o Java. Para Este tem argumentos estáticos que retornará um objeto que implementa
ver como o invokedynamic funciona, contém um manipulador para o méto- a interface Function.
discutiremos como as chamadas de do sintetizado (veja última seção) e a Quando uma instrução invoke-
método Java são compiladas em by- assinatura correta para o lambda. dynamic termina, um objeto que im-
tecode. O meta-factory retorna um CallSite plementa Function e que tenha uma
Uma chamada padrão de método que contém um manipulador de mé- expressão lambda como conteúdo do
Java será convertida em um pedaço todo e que, por sua vez, retorna uma método apply() é colocado no topo da
de bytecode da JVM, que é frequen- instância do tipo correto que a expres- fila, e o resto do código pode seguir
temente referenciado como uma cha- são lambda foi convertida. Logo, uma normalmente.
mada local. Esta chamada é composta
de um código de operação de envio
(tal como invokevirtual, para chama- Conclusão
das de método de instância normal) Obter expressões lambda na plataforma Java sempre foi e vai ser uma tarefa
e uma constante (um deslocamento desafiadora, mas garantindo que o terreno adequado estava no lugar, o Java 7
para o Constant Pool da classe) que facilitou consideravelmente esse esforço. O plano B não só forneceu aos desen-
indica qual é o método a ser chamado. volvedores o lançamento antecipado do Java 7, mas também permitiu que as
Os diferentes códigos de invocação principais tecnologias realizassem testes em produção antes de usarem o Java 8
têm regras diferentes que definem e especialmente expressões lambda.
como a pesquisa de método é feita,
mas até Java 7 sempre eram utilizadas
constantes para saber diretamente
qual o método a ser chamado.
O invokedynamic é diferente. Ao
Sobre o Autor
invés de fornecer uma constante que
indica diretamente qual método deve
ser chamado, o invokedynamic forne-
ce um mecanismo de indireção que
permite o código do usuário decidir Ben Evans é o CEO da jClarity, uma startup que fornece ferramentas de
qual método chamar em tempo de desempenho para auxiliar equipes de desenvolvimento e ops. Ele é um or-
execução. ganizador no LJC (JUG Londres) e membro do comitê executivo do JCP, aju-
Quando a primeira chamada com dando a definir padrões para os ecossistemas Java. Ele é um Java Cham-
invokedynamic é encontrada, o alvo
pion; JavaOne Rockstar; coautor do “The Well-Grounded Java Developer”
ainda não é conhecido. Ao invés dis-
e um palestrante público na plataforma Java, desempenho, concorrência
so, um manipulador de método (cha-
mado método inicial) é invocado.
e tópicos relatados.

eMag | Java: Presente e Futuro 35


Q&A: NOVIDADES DO JAVA 8
por Matt Raible, tradução de Diogo Carleto
O Java 8 é uma das atualizações de linguagem de programação mais esperadas dos últimos anos. O novo release contém a API de datas, API de
stream e os lambdas, remove o permgen e traz um longo conjunto de melhorias. Para aprender mais sobre este lançamento, conversamos com
Georges Saab, vice-presidente de desenvolvimento de software do Java Platform Group na Oracle.

InfoQ: Para os que não têm segui-


do o projeto Lambda de perto, poderia
nos dar uma ideia do que foi envolvi-
do nesta implementação? Talvez seja
a primeira vez que tanto a linguagem
como a VM e as bibliotecas evoluíram
juntas de maneira coordenada.

A maioria das grandes funcionalidades


em versões anteriores foi feita de manei-
ra que somente uma dessas três áreas foi
afetada; ou as mudanças em cada área fo-
ram introduzidas ao longo de uma série de
grandes releases. Com o projeto Lambda muito mais fácil experimentar com uma demanda, assim como as operações inter-
no Java 8, fizemos um mudanças coordena- linguagem com poucos milhares de desen- mediárias de streams, permite ganhos de
das, envolvendo a linguagem, as bibliote- volvedores que com muitos milhões. Nosso eficiência importantes. Isso porque várias
cas e a JVM. Ao longo do desenvolvimento, enfoque tem sido em abordar os aspectos operações podem ser realizadas em uma
cada área influenciou e fortaleceu o design que melhoram a vida dos milhões de pro- única passagem sobre os dados. E com oti-
e a implementação das demais. gramadores Java, evoluindo a plataforma e mizações importantes da JVM nos bastido-
Experimentamos, por exemplo, com im- a linguagem de forma consciente e respon- res possibilitado pelo design dos lambdas,
plementações alternativas do Lambda na sável. o impacto de filtros adicionais pode ser re-
JVM e descobrimos que poderíamos utili- duzido em boa parte.
zar o InvokeDynamic. Ao fazê-lo, encontra- InfoQ: A combinação do Lambda Outro ponto a ser considerado é que a
mos pontos que poderiam ser melhorados e da Streams API ajuda a desenvolver utilização do paralelismo com Streams e
no próprio InvokeDynamic. O desejo de código limpo e conciso, mas foram Lambdas foi simplificado. As operações de
utilizar Lambdas de forma natural com as levantadas preocupações quanto ao streams em paralelo podem se beneficiar
Collections nos levou ao design da Streams impacto no desempenho, na medida da diminuição das restrições de ordenação,
API e depois aos métodos de extensão – os que filtros são aplicados seguidamen- em que os usuários não conhecem conflitos
quais exigiram suporte da linguagem. te para reduzir conjuntos de maneira de ordenação do stream subjacente.
Tem sido um processo evolutivo ao lon- funcional. Quais otimizações foram
go de vários anos, com bastante feedback introduzidas para reduzir esse im- InfoQ: Outra funcionalidade im-
da comunidade. pacto? portante do Java 8 são as Annotations
nos tipos do Java, para permitir que
InfoQ: Você acredita que a adição As Streams permitem operações inter- verificadores de tipos “plugáveis” se-
de lambdas irá trazer de volta ao Java mediárias e terminais. As operações inter- jam desenvolvidos. Poderia nos falar
os desenvolvedores Groovy e Scala? mediárias, como filtragem, não executam um pouco mais sobre isso?
nenhuma filtragem em si; criam um novo
É importante lembrar que essas duas Stream, que quando percorrido, fornece os Essa funcionalidade permite o uso de
linguagens (e muitas outras) executam na elementos que correspondem a um dado anotações nos nomes dos tipos, na maio-
JVM. Trabalhamos muito para suportar predicado. ria dos lugares onde estes tipos podem ser
outras linguagens além do Java na plata- Dessa forma, por um lado, a criação de usados. Como resultado da mudança, os
forma, e sinto que há muito que os imple- filtros adicionais poderia resultar em traba- desenvolvedores podem agora escrever
mentadores de linguagens podem apren- lho adicional em tempo de execução; por anotações para detectar condições de erros
der com essas experiências. É claro que é outro, o processamento de streams sob em tempo de compilação, usando verifica-

36 InfoQ Brasil
dores de tipos plugáveis. Esses verificado- InfoQ: Preocupações com Java e Uma das muitas novas funcionalidades
res e esquemas de anotações estão sendo segurança tiveram muito destaque no Java SE 8 é o suporte a Compact Profiles
desenvolvidos na comunidade para erros nos últimos tempos. O Java 8 traz me- (perfis compactos), que definem subcon-
de null-pointer, locking e internacionaliza- lhorias nessa área, no plug-in do Java juntos de perfis da plataforma Java SE. Isso
ção. ou em partes relacionadas? permite que aplicações que não requerem
Uma boa fonte de informação e imple- toda a plataforma sejam publicadas e exe-
mentação é o Checker Framework do Prof. Uma série de melhorias importantes de cutadas em dispositivos com menor capa-
Michael Ernst do checker-framework.org, segurança e novas funcionalidades foram cidade.
que inclui um checker para não-nulos, den- entregues como parte das atualizações do No mais, houve outras melhorias no
tre mais de uma dúzia dessas ferramentas. Java SE 7, incluindo Deployment Rule Sets HotSpot, como a redução do tamanho de
Ernst também atuou como líder da co-spec (uma funcionalidade para empresas que metadados de classes e o tamanho da VM
na JSR 308, no qual esta funcionalidade da gerenciam o seu ambiente de desktop Java em geral. Com isso o JDK 8 pode ser esca-
linguagem foi especificada. diretamente) e Exception Site Lists (lista de lado para o desenvolvimento de aplicativos
Seria ótimo ver os resultados de pelo sites de exceção). A segurança no Java é e a implantação em pequenos dispositivos.
menos um desses esquemas de anotações uma de nossas prioridades. E a nova ferramenta jdeps que vem com o
sendo aplicado sobre a base de código da Além disso, o Java SE 8 contém funcio- JDK 8 permite descobrir de qual Profile o
JDK no futuro; e ver a comunidade mais nalidades novas de segurança. As mais código sua aplicação depende.
ampla de desenvolvedores Java começar perceptíveis são as na implementação do Vindo de outra direção, o Java ME 8 está
a utilizar esta tecnologia em suas próprias Transport Layer Security: TLS 1.2. Este é sendo aprimorado a se alinhar mais com o
bases de código, além de desenvolver no- agora o padrão na plataforma. Em termos Java SE 8, quando a linguagem, VM e biblio-
vos verificadores para outros aspectos de globais de APIs de segurança, existe uma tecas. Ainda não é possível utilizar lambdas
qualidade de software. série de outras melhorias, desde aperfei- em código Java ME 8, mas a plataforma
Especialmente com respeito a sistemas çoamentos na verificação de revogação de agora suporta construções de linguagem
embarcados e outros em que a segurança certificados, até o uso de novos algoritmos Java introduzidas no Java SE 1.5, 6 e 7, como
seja crítica, esse tipo de inovação permiti- de criptografia. assertions, generics, enumerations, strings
ria que propriedades cruciais e restrições em switches, declarações try-with-resour-
de tipos e seu uso fossem qualificados e InfoQ: Você sabe qual o percen- ces e o operador diamond.
analisado estatisticamente, como parte do tual de desenvolvedores Java usando Da mesma forma, as classes das biblio-
processo de compilação. É um caminho Java 5, 6 e 7? Existe algum plano para tecas do núcleo do Java foram atualizadas
para usuários de outras linguagens nesse acelerar a adoção do Java 8? com suporte para protocolos web moder-
domínio migrarem para a plataforma Java. nos, como IPv6 e funcionalidades avança-
Ao longo dos últimos seis a nove meses, das de segurança, incluindo o suporte para
InfoQ: Para linguagens dinâmi- tenho falado em conferências ao redor do TLS 1.2. Isso torna as plataformas Java SE e
cas, quais são as principais melhorias mundo e toda vez pergunto qual versão Java ME mais próximas do que nunca.
no Java 8, em sua opinião? estão usando. Apoiado sobre essa pesquisa
informal e não científica, diria que a maior InfoQ: Quando veremos a funcio-
São as melhorias de performance na parte dos desenvolvedores Java estão nalidade de Stripped Implementa-
Máquina Virtual HotSpot em geral e no usando o Java SE 7 hoje, com minoria (sig- tions adicionadas ao Java? (Stripped
invokedynamic em particular. Outra nova nificativa) ainda usando na versão 6, e um Implementations permitem que uma
funcionalidade significativa é o engine Ja- número pequeno em versões mais antigas. implementação específica do Java SE
vaScript Nashorn. Melhorar o desempenho Do ponto de vista do desenvolvedor, o seja empacotada com a biblioteca Java
do Nashorn nos ajudou a encontrar novas Java SE 8 tem muitas razões convincentes e o código da aplicação. Elementos
oportunidades de otimização da VM para para a rápida adoção, como os novos recur- desnecessários são omitidos parcial-
implementações de linguagens dinâmicas. sos da linguagem e APIs. E com IDEs como mente ou por inteiro.)
Além disso, o Nashorn agora fornece NetBeans, Eclipse e IntelliJ IDEA trabalhan-
uma maneira conveniente de usar o Java a do para oferecer suporte aos novos recur- Precisaremos voltar a examinar como a fun-
partir do JavaScript, permitindo que apli- sos, espero ver os desenvolvedores adotar cionalidade de Stripped Implementations pode
cações JavaFX inteiras sejam escritas em o Java 8 rapidamente. ser adicionada à plataforma em uma versão an-
JavaScript e executadas na JVM. Essa inte- terior à 9. Não se trata de um problema técnico,
roperabilidade transparente entre o Java e InfoQ: Um dos principais temas mas sim de garantir que o texto de especifica-
linguagens dinâmicas executando na JVM, do JavaOne 2013 foi a unificação do ção e aspectos jurídicos permitam a utilização
oferece uma maneira poderosa de se escre- Java ME, SE e EE. Até que ponto o Java em vários cenários, ao mesmo tempo evitando
ver aplicações web. 8 caminhou nessa direção? que haja fragmentação da plataforma Java.

eMag | Java: Presente e Futuro 37


DO GROOVY AO JAVA 8
por Dan Woods, traduzido por Daniel Sousa
Este artigo focará nas semelhanças entre o Groovy e o Java 8, e vai demonstrar o quão familiar os conceitos do Groovy se traduzem para Java 8.

D
esenvolvedores Groovy terão mais facilidade def closure = {
para adotar os conceitos e novas construções “called”
da linguagem oferecida pelo Java 8. Muitas das }
melhorias oferecidas na próxima versão do Java são assert closure instanceof java.util.concurrent.Callable
características que o Groovy oferece há anos. Desde assert closure() == “called”
uma nova sintaxe até estilos de programação funcional,
lambdas, coleção de streams, e referências de métodos Podemos fazer o Groovy implementar outras interfaces
como cidadãos de primeira classe. Os desenvolvedores funcionais por meio da conversão de tipos closures.
Groovy terão uma vantagem ao escrever o código Java no
futuro. Este artigo focará nas semelhanças entre o Groovy public interface Function {
e o Java 8, e vai demonstrar o quão familiar os conceitos def apply();
do Groovy se traduzem para Java 8. }
Começaremos discutindo estilos de programação, def closure = {
como atualmente utilizamos a programação funcional no “applied”
Groovy, e de que forma as construções em Java 8 oferecem } as Function
um estilo de programação melhor. assert closure instanceof Function
Closures são, talvez, o melhor exemplo de programação assert closure.apply() == “applied”
funcional em Groovy. Por baixo dos panos, uma closure
em Groovy é apenas a implementação de uma interface Closures e programação funcional se traduzem bem
funcional. Uma interface funcional é qualquer interface em Java 8. Interfaces funcionais são muito importantes
que possua apenas um único método para implementar. na próxima versão do Java, pois o Java 8 oferece
Por padrão, as closures do Groovy são uma implementação implementação implícita de interfaces funcionais com a
da interface funcional Callable, implementando o método introdução das funções Lambda.
“call”. As funções lambda podem ser pensadas, e utilizadas

38 InfoQ Brasil
como as closures em Groovy. Implementar uma interface return getAttribute(key);
funcional em Java 8 oferece simplicidade semelhante a }
das closures em Groovy. default Map getScope() {
return scopeMap;
Callable callable = () -> “called”; }
assert callable.call() == “called”; }
static final WebFlowScope scope =
É importante notar também que as funções lambda de (Object key) -> “edited_” + scope.getScope().get(key);
uma só linha oferecem retorno implícito, assim como no assert scope.put(“attribute”, “val”) == “val”;
Groovy.
No futuro, o Groovy também oferecerá implementação No Java 8, métodos default de interface podem também
implícita de Interfaces Funcionais para as closures, ajudar-nos a implementar características do Groovy
semelhante a oferecida pelo Java 8. Esta característica como memoization e trampoline. Memoization pode ser
da as closures a capacidade de aproveitar as variáveis implementada simplesmente criando-se uma interface
de instância e métodos sem derivar totalmente uma funcional com um método de interface default para
subclasse concreta. computar deterministicamente um resultado ou obter o
resultado do cache.
abstract class WebFlowScope {
private static final Map scopeMap = [:] public interface MemoizedFunction<T, R> {
abstract def getAttribute(def name); static final Map cache = new HashMap();
public def put(key, val) { R calc(T t);
scopeMap[key] = val public default R apply(T t) {
getAttribute(key) if (!cache.containsKey(t)) {
} cache.put(t, calc(t));
protected Map getScope() { }
scopeMap return (R)cache.get(t);
} }
} }
WebFlowScope closure = { name -> static final MemoizedFunction<Integer, Integer> fib = (Integer n) -> {
“edited_${scope[name]}” if (n == 0 || n == 1) return n;
} return fib.apply(n - 1)+fib.apply(n-2);
assert closure instanceof WebFlowScope };
assert closure.put(“attribute”, “val”) == “edited_val” assert fib.apply(20) == 6765;

Em Java 8, as Interfaces Funcionais com métodos De maneira similar, podemos utilizar métodos default
default na interface oferecem uma boa aproximação deste de interface em Java 8 para desenvolver implementação
conceito. Métodos default em interfaces são algo novo Trampoline. Trampoline é uma estratégia de recursão
em Java. Eles foram concebidos para permitir melhorias que não sobrecarrega a pilha de chamadas do Java, e é
nas APIs principais do Java sem violar os contratos um recurso muito útil do Groovy quando uma recursão
de implementações feitas em versões anteriores da profunda é necessária.
linguagem.
As funções lambda também terão acesso a métodos interface TrampolineFunction<T, R> {
padrão da interface em que são definidas. Isto significa R apply(T...obj);
que APIs robustas podem ser construídas diretamente public default Object trampoline(T...objs) {
em uma interface, dando recursos aos programadores Object result = apply(objs);
sem alterar a natureza do tipo ou do contrato no qual o if (!(result instanceof TrampolineFunction)) {
tipo pode ser utilizado. return result;
} else {
public interface WebFlowScope { return this;
static final Map scopeMap = new HashMap(); }
Object getAttribute(Object key); }
default public Object put(Object key, Object val) { }
scopeMap.put(key, val); // Encapsula a chamada do TrampolineFunction para evitar um

eMag | Java: Presente e Futuro 39


StackOverflowError operações em cadeia em listas.
static TrampolineFunction<Integer, Object> fibTrampoline = List<Integer> list = new ArrayList<>();
(Integer...objs) -> { list.add(1); list.add(2);
Integer n = objs[0]; list.add(3); list.add(4);
Integer a = objs.length >= 2 ? objs[1] : 0; List<Integer> newList =
Integer b = objs.length >= 3 ? objs[2] : 1; list.stream().map((Integer n) -> n * 5).collect(Collectors.
if (n == 0) return a; toList());
else return fibTrampoline.trampoline(n-1, b, a+b); assert newList.get(0) == 5 && newList.get(1) ==
}; 10 && newList.get(2) == 15 && newList.get(3) == 20;

Além dos recursos básicos das closures e dos recursos O Groovy também oferece atalhos para filtrar listas
mais avançados como Memoization e Trampolining, através do método ‘findAll’.
alguns dos recursos mais práticos e úteis que o Groovy
tem para oferecer estão relacionados às extensões da def emails = [‘danielpwoods@gmail.com’, ‘nemnesic@gmail.com’,
linguagem para a API Collections. Em Groovy, podemos ‘daniel.woods@objectpartners.com’, ‘nemnesic@nemnesic.com’]
utilizar estas extensões para escrever atalhos e realizar def gmails = emails.findAll { it.endsWith(‘@gmail.com’) }
operações em listas usando o método ‘each’. assert gmails = [‘danielpwoods@gmail.com’, ‘nemnesic@gmail.com’]
De maneira semelhante, em Java 8 os desenvolvedores podem filtrar
def list = [1, 2, 3, 4] uma lista utilizando a API Stream.
list.each { item -> List<String> emails = new ArrayList<>();
println item emails.add(“danielpwoods@gmail.com”);
} emails.add(“nemnesic@gmail.com”);
emails.add(“daniel.woods@objectpartners.com”);
Java 8 introduz um conceito similar ao do Groovy emails.add(“nemnesic@nemnesic.com”);
no que diz respeito a iterar coleções, disponibilizando o List<String> gmails = emails.stream().filter( (String email) ->
método ‘forEach’, que substitui a maneira convencional de email.endsWith(“@gmail.com”) ).collect(Collectors.toList());
percorrer listas. assert gmails.get(0) == “danielpwoods@gmail.com” && gmails.get(1) ==
“nemnesic@gmail.com”;
List<Integer> list = new ArrayList<>();
list.add(1); list.add(2); As extensões da API Collections do Groovy tornam
list.add(3); list.add(4); fácil a ordenação de listas fornecendo à API um método
list.forEach( (Integer item) -> System.out.println(item); ); ‘sort’. O método ‘sort’ também utilizará uma closure que
converte para um comparador durante a ordenação da
Além da iteração simplificada, o Groovy dá aos lista se uma lógica de ordenação especial for necessária.
desenvolvedores uma variedade de outros atalhos Adicionalmente, se uma simples reversão da ordem da
quando se trabalha com listas. O método “collect”, por lista é necessária, o método ‘reverse’ pode ser chamado e
exemplo, é a abreviação para mapear elementos de uma a ordem invertida.
lista para novos tipos ou valores, coletando os resultados
em uma nova lista. def list = [2, 3, 4, 1]
assert list.sort() == [1, 2, 3, 4]
def list = [1, 2, 3, 4] assert list.sort { a, b -> a-b <=> b } == [1, 4, 3, 2]
def newList = list.collect { n -> n * 5 } assert list.reverse() == [2, 3, 4, 1]
assert newList == [5, 10, 15, 20]
Trabalhando novamente com a API de Stream do Java
Na implementação do Groovy, o método ‘collect’ recebe 8, podemos ordenar a lista usando o método ‘sorted’ e
um mapeamento como argumento, enquanto o Java 8 obter o resultado usando o método ‘toList’ do Collectors.
oferece uma implementação um pouco mais verbosa. O método ‘sorted’ pode receber opcionalmente uma
Usando a API Stream, os desenvolvedores podem realizar função de comparação como argumento (tal como uma
a mesma estratégia de mapeamento e coleta chamando função Lambda), então uma lógica de ordenação especial
o método ‘map’ no componente ‘stream’ da lista, em e reversão dos itens da lista são operações facilmente
seguida, chamar o método ‘collect’ a partir do stream que realizadas.
é retornado na etapa de mapeamento. A API Stream dá
aos desenvolvedores a capacidade de efetuar facilmente List<Integer> list = new ArrayList<>();

40 InfoQ Brasil
list.add(2); list.add(3); strings.add(“item3”);
list.add(4); list.add(1); strings = strings.stream().map(Helpers::modifier).collect(Collectors.
list = list.stream().sorted().collect(Collectors.toList()); toList());
assert list.get(0) == 1 && list.get(3) == 4; assert “edited_item1”.equals(strings.get(0));
list = list.stream().sorted((Integer a, Integer b) -> assert “edited_item2”.equals(strings.get(1));
Integer.valueOf(a-b).compareTo(b)).collect(Collectors.toList()); assert “edited_item3”.equals(strings.get(2));
assert list.get(0) == 1 && list.get(1) ==
4 && list.get(2) == 3 && list.get(3) == 2; Os métodos de referência podem ser passados como
list = list.stream().sorted((Integer a, Integer b) -> b.compareTo(a)). argumentos para qualquer método que necessita de uma
collect(Collectors.toList()); interface funcional. Por sua vez, os métodos de referência
assert list.get(0) == 2 && list.get(3) == 1; terão a forma de interfaces funcionais e podem ser
tratadas como tal.
Quando usando APIs fluentes, como stream de lista,
isso pode rapidamente ser insustentável para tratar public interface MyFunctionalInterface {
todos os processamentos dentro de uma função closure boolean apply();
ou Lambda. Isso faz sentido, em alguns casos, como }
delegar o processamento para um método que é adaptado void caller(MyFunctionalInterface functionalInterface) {
especialmente para essa unidade de trabalho. assert functionalInterface.apply();
No Groovy, podemos fazer isso passando a referência }
de um método dentro da função. Uma vez que um método boolean myTrueMethod() {
é referenciado usando o operador ‘.&’, ele é convertido para return true;
uma função closure e pode ser passado para outro método }
como argumento. Intrinsecamente, isso proporciona caller(Streaming::myTrueMethod);
flexibilidade na implementação, uma vez que o código de
processamento pode ser introduzido de fontes externas. No Java 8, os desenvolvedores de bibliotecas podem
Os desenvolvedores podem agora organizar logicamente fazer mudanças nos contratos das interfaces sem que os
o processamento dos métodos obtendo uma arquitetura consumidores tenham que atualizar a forma de interagir
de aplicação mais fácil de ser mantida e sustentável. com as bibliotecas.
A tradução perfeita dos conceitos e estilos de
def modifier(String item) { programação do Groovy para o Java 8 é uma ponte
“edited_${item}” importante entre duas linguagens. O Groovy foi adotado
} em grande escala no domínio da JVM por causa das
def list = [‘item1’, ‘item2’, ‘item3’] flexibilidades de herança e melhorias nas APIs existentes
assert list.collect(this.&modifier) == [‘edited_item1’, ‘edited_ do Java. Com muitas dessas melhorias enraizando no
item2’, ‘edited_item3’] Java 8, isso significa que a similaridade entre as duas
Desenvolvedores no Java 8 dispõem da mesma flexibilidade através do linguagens estão começando a superar as diferenças, um
uso do operador ‘::’ para obter uma referência do método. fato que este artigo pretende delinear. Para finalizar, os
List<String> strings = new ArrayList<>(); desenvolvedores que possuem experiência em Groovy
strings.add(“item1”); terão uma curva de aprendizado pequena para aprender
strings.add(“item2”); e adaptar as novas APIs, funcionalidades e conceitos

Sobre o Autor
Daniel pode ser contatado através do email
danielpwoods@gmail.com ou pelo Twitter
@danveloper.

Daniel Woods é consultor sênior na Object Partners, Inc. Ele é especialista


em Arquitetura de Aplicações com Groovy e Grails, mantendo forte interes-
se em Java e outras linguagens baseadas na JVM.

eMag | Java: Presente e Futuro 41


NASHORN: COMBINANDO O PODER DO JAVA E
JAVASCRIPT NO JDK 8
por Oliver Zeigermann, traduzido por Rafael Sakurai
No JDK 8, o Nashorn substituiu o Rhino como motor padrão de JavaScript do Java por oferecer melhorias de desempenho e compatibilidade.
O Avatar.js trouxe o popular modelo de programação do Node para o Nashorn, permitindo que muitos servidores de aplicações JavaScript possam ser
executados no ambiente Java.

D
esde o JDK 6, o Java foi liberado contendo um Isso fornece um desempenho de 2 a 10x a mais
motor de JavaScript com base no Rhino da que a antiga implementação do Rhino, apesar de ter o
Mozilla. Essa funcionalidade permite embarcar desempenho um pouco inferior ao V8, o motor dentro
código JavaScript dentro do Java e até chamar no Java o do Chrome e Node.js. Se estiver interessado nos detalhes
código JavaScript embarcado. Além disso, ele permite da implementação dê uma olhada nesses slides do JVM
a execução de JavaScript através de linha de comando Language Summit de 2013.
usando o jrunscript. Isso é bom o suficiente quando Como o Nashorn vem com o JDK 8, ele dá suporte às
não há necessidade de muito desempenho e é possível interfaces funcionais, como veremos em mais detalhes
conviver com um conjunto limitado das funcionalidades adiante.
do ECMAScript 3. Vamos começar com um exemplo bem simples. Primeiro
Começando com o Nashorn do JDK 8 atualizando o será necessário instalar o JDK 8 e o NetBeans, IntelliJ IDEA
Rhino como motor embarcado de JavaScript no Java. O ou Eclipse. Essas IDEs fornecem ao menos o suporte básico
Nashorn fornece suporte completo para a especificação de JavaScript integrado com o desenvolvimento. Vamos
do ECMAScript 5.1 com mais algumas extensões. Permite criar um simples projeto Java contendo dois arquivos de
compilar o JavaScript em bytecode Java usando as novas exemplo e em seguida executaremos o programa, como
funcionalidades da linguagem com base na JSR 292, mostrado na figura a seguir:
incluindo o invokedynamic, que foi introduzido no JDK 7.

42 InfoQ Brasil
Na linha 12 usamos o método “eval” para avaliar world” direto como argumento para o “eval”, mas
qualquer código JavaScript. Nesse caso apenas ter o JavaScript em seu próprio arquivo abre todo um
carregamos o arquivo JavaScript principal e o mundo de ferramental para ele.
avaliamos. Não se preocupe com o “print” no código, Atualmente o Eclipse não possui um suporte
ele pode não parecer familiar porque não construímos dedicado para o Nashorn através do projeto da
essa função no JavaScript, mas o Nashorn fornece Ferramenta de Desenvolvimento de JavaScript (JSDT),
essa e outras funções por conveniência, que são no entanto suporta o ferramental básico e a edição de
convenientes no ambiente de scripting. Também seria JavaScript.
possível passar o comando de impressão do “hello

eMag | Java: Presente e Futuro 43


O IntelliJ IDEA 13.1 (edição da comunidade e final) modificará as referências correspondentes entre as
fornece excelente suporte ao JavaScript e Nashorn. Há linguagens.
funcionalidades completas para depurar e também A seguir temos um exemplo que permite depurar
permitir o refatoramento que sincroniza o Java com o uma chamada ao JavaScript através do Java (note que
JavaScript; então por exemplo, se renomear uma classe o NetBeans também fornece depuração de JavaScript
Java que é referenciada no JavaScript ou se renomear como mostrado na figura a seguir):
um arquivo JavaScript que é usado no Java, a IDE

Pode-se dizer que o ferramental é bom e que a nova lo sem argumentos para abrir o modo interativo, ou
implementação corrige os problemas de desempenho pode informar o nome do arquivo JavaScript que
bem como o problema de estar em conformidade com deseja executar, ou pode usar para substituir o shell
o JavaScript, mas por que devemos usa-lo? Uma razão script, exemplo:
pode ser o script em geral. Algumas vezes pode ser útil
para tratar alguns tipos de strings e deixar apenas que #!/usr/bin/env jjs
seja interpretada. Algumas vezes pode ser bom não
ter um compilador no caminho ou não se preocupar var name = $ARG[0];
com tipos estáticos, ou talvez o interesse no modelo de print(name ? “Hello, ${name}!” : “Hello, world!”);
programação do Node.js, que pode ser usado no Java
como veremos no final desse artigo. Há também o caso Para passar argumentos no programa através do
do desenvolvimento no JavaFX que será muito mais jjs, utilize o prefixo “--”. Dessa forma podemos ter
rápido usando JavaScript do que apenas Java. uma chamada como a seguinte:
O motor do Nashorn pode ser executado através da
./hello-script.js -- Joe

Shell scripts Sem o prefixo “--”, o parâmetro será interpretado


linha de comando usando o comando jjs. Pode executa- como o nome do arquivo.

44 InfoQ Brasil
Passando dados para o Java e vice-versa }
Como mencionado anteriormente, é possível });
chamar o JavaScript direto do código Java através var th = new MyThread();
do motor chamado “ScriptEngine” e chamando seu th.start();
método “eval”. É possível passar dados explicitamente th.join();
como strings ...
Note que a maneira canônica de acessar uma classe
ScriptEngineManager scriptEngineManager através do Nashorn é usando o Java.type e estendendo
= new ScriptEngineManager(); uma classe através do Java.exend.
ScriptEngine nashorn = scriptEngineManager.
getEngineByName(“nashorn”);
String name = “Olli”; Linguagem funcional
nashorn.eval(“print(\’” + name + “\’)”); Por todos os aspectos, com o lançamento do JDK
8, o Java tornou-se - pelo menos até certo ponto - uma
… ou pode passar referências do Java que podem linguagem funcional. Agora é possível usar funções
ser acessadas como variáveis globais dentro do motor de ordem superior nas coleções, por exemplo para
de JavaScript: iterar sobre um conjunto de elementos. Uma função
de ordem superior é uma função que tem outra função
int valueIn = 10; como parâmetro e faz algo significativo com ela. Veja
SimpleBindings simpleBindings = new SimpleBindings(); um exemplo em Java:
simpleBindings.put(“globalValue”, valueIn);
nashorn.eval(“print (globalValue)”, simpleBindings); List<Integer> list = Arrays.asList(3, 4, 1, 2);
O resultado da execução do JavaScript é devolvido list.forEach(new Consumer() {
através do método “eval” do motor: @Override
Integer result = (Integer) nashorn.eval(“1 + 2”); public void accept(Object o) {
assert(result == 3); System.out.println(o);
}
});
Usando classes Java no Nashorn
Como mencionado anteriormente, uma das Nesse exemplo, ao invés de iterar sobre os
funcionalidades mais poderosas do Nashorn é o uso de elementos usando um laço “externo” como fazemos
classes do Java dentro do JavaScript. É possível tanto tradicionalmente, agora passamos uma função
acessar as classes e criar instâncias como também “Consumer” para o método “forEach”, uma operação
criar subclasses delas, chamar membros estáticos de ordem superior realiza um “laço interno” e executa
e fazer virtualmente qualquer coisa que é possível o método “accept” do Consumer, percorrendo cada
diretamente no Java. elemento da coleção, um a um.
Como um exemplo, vamos dar uma olhada em Como mencionado, a abordagem da linguagem
threads. O JavaScript não tem nenhuma funcionalidade funcional para tal função de ordem superior aceitaria
da linguagem para tratar concorrência e todos os um parâmetro de função, em vez de um objeto. A
ambientes de execução comuns são de processos passagem como referências para as funções em si, não é
únicos ou pelo menos sem qualquer compartilhamento algo tradicional fornecido no Java, o JDK 8 agora possui
de estado. É interessante ver que no ambiente do alguns tipos sintáticos para expressar justamente o
Nashorn o JavaScript pode de fato ser executado uso de expressões lambda (também conhecidas como
concorrentemente e com compartilhamento de estado, “closures”). Por exemplo:
tal como no Java:
List<Integer> list = Arrays.asList(3, 4, 1, 2);
// é assim que obtemos acesso à classe Thread do Java. list.forEach(el -> System.out.println(el));
var Thread = Java.type(“java.lang.Thread”);
Nesse caso o parâmetro para o “forEach” tem o
// cria a subclasse com o método run. formato de uma referência de função. Isso é possível
var MyThread = Java.extend(Thread, { porque o Consumer é uma interface funcional (algumas
run: function() { vezes chamado de tipo de Método Abstrato Simples, ou
print(“Run in separate thread”); do inglês “Single Abstract Method - SAM”).

eMag | Java: Presente e Futuro 45


Então, porque abordamos lambdas na discussão extensões que são usadas na documentação da Oracle
sobre Nashorn? Porque no JavaScript podemos e podemos nos familiar com elas.
escrever códigos como esse e o Nashorn está Primeiro vamos configurar o cenário para a
especialmente preparado para fazer a ligação entre o primeira extensão. Como visto anteriormente
Java e o JavaScript nesse caso. Em particular, porque podemos estender classes Java através do JavaScript
permite passar funções escritas em JavaScript como usando o Java.extend. Se quiser criar uma subclasse de
implentações de interfaces funcionais (tipo SAM). uma classe Java abstrata ou implementar um interface
Vejamos alguns simples exemplos de código podemos usar uma sintaxe mais conveniente. Nesse
JavaScript que fazem coisas iguais as feitas com caso é possível chamar virtualmente o construtor
código Java. Note que não há uma forma de de uma classe abstrata ou interface e passar um
construção de listas no JavaScript, apenas arrays; mas objeto literal JavaScript que descreve os métodos
esses arrays são dimensionados dinamicamente e implementados. As literais do objeto JavaScript são
tem métodos para comparação deles com uma lista apenas pares de nome e valor, muito parecido com
em Java. Então, nesse exemplo estamos chamando o o formato JSON. Nesse exemplo foi implementado a
método “forEach” de um array em JavaScript: interface Runnable:

var jsArray = [4,1,3,2]; var r = new java.lang.Runnable({


jsArray.forEach(function(el) { print(el) } ); run: function() {
print(“running...\n”);
A similaridade é óbvia; mas isso não é tudo. }
Podemos também converter um array em JavaScript });
para uma lista em Java:
Nesse exemplo estamos virtualmente chamando
var list = java.util.Arrays.asList(jsArray); o construtor de Runnable com um objeto literal que
especifica a implementação do método run. Note que,
Esse código JavaScript executa dentro do Nashorn. isso é algo que a implementação do Nashorn possui,
Como isso agora é uma lista do Java, podemos em outros casos isso não seria possível apenas com
chamar o método “forEach”. Note que esse não é o JavaScript.
mesmo método “forEach” que chamamos no array O código desse exemplo é bem parecido com a
em JavaScript, mas sim o método “forEach” definido implementação de uma interface usando uma classe
nas collections. Ainda, podemos passar uma função interna anônima em Java. Isso nos leva a primeira
simples em JavaScript: extensão, que deixa passar o último parâmetro após o
parênteses “)” de fechamento durante a chamada do
list.forEach(function(el) { print(el) } ); construtor. Fazendo isso, o código ficaria como esse ...

O Nashorn permite que passemos funções em var r = new java.lang.Runnable() {


JavaScript como referência, nos locais que esperam run: function() {
interfaces funcionais (tipo SAM). Portanto, isso não print(“running...\n”);
é possível apenas no Java, mas também no JavaScript. }
A próxima versão do ECMAScript - que espera- };
se a versão final para esse ano - incluirá uma sintaxe
curta para funções que permitirá códigos similares … que faz exatamente a mesma coisa, mas tem
aos lambdas em Java, exceto que no JavaScript será uma semelhança ainda maior com o Java.
usado seta dupla =>. Isso facilitará ainda mais o A segunda extensão mais usada é um atalho
alinhamento entre as linguagens. para as funções que permite omitir ambas as chaves
bem como a instrução de retorno, para que o corpo
do método possa ser em uma única linha. Assim, o
Dialeto especial do JavaScript no Nashorn exemplo da sessão anterior ...
O Nashorn suporta atualmente a versão 5.1
do ECMAScript e mais algumas extensões. Não list.forEach(function(el) { print(el) } );
recomendo o uso dessas extensões porque não se … pode ser expresso de forma ligeiramente mais conciso:
parecem com Java e nem JavaScript, parece algo não list.forEach(function(el) print(el));
natural para os desenvolvedores. No entanto há duas

46 InfoQ Brasil
Avatar.js O objetivo do Avatar.js é fornecer a mesma
Vimos que com o Nashorn temos um bom motor API central como o Node ligando o libuv com as
de JavaScript embarcado no Java. Também vimos que classes Java e então torná-lo acessível ao JavaScript.
o Nashorn pode acessar as classes do Java. O Avatar.js Mesmo que isso possa parecer complicado, funciona
vai um passo além e traz “o modelo de programação surpreendemente bem. O Avatar.js suporta diversos
do Node, APIs e os módulos do ecossistema para a módulos Node e suporta o “express” - o principal
plataforma Java”. Para entender o que isso significa framework web para Node - indicando que isso pode
e porque é excitante, primeiro vamos entender o que funcionar com diversos projetos existentes.
é o Node. O Avatar.js possui uma distribuição binária que
O Node é basicamente uma extração do motor de pode ser encontrada no site do projeto bem como os
JavaScript V8 do Chrome que pode ser executado passos para a sua instalação.
através de linhas de comando, sem precisar de Um vez que tenha configurado os binários e
um navegador. Isso permite que o JavaScript seja colocados na pasta lib, podemos então chamar o
executado não apenas no navegador, mas também no framework Avatar.js usando algo como:
lado servidor. Para executar o JavaScript no servidor
de uma forma significativa, será necessário acessar java -Djava.library.path=lib -jar lib/
pelo menos o sistema de arquivos e a rede. Para fazer avatar-js.jar helloWorld.js
isso, o Node possui uma biblioteca chamada libuv
que faz isso de maneira assíncrona. Na prática, isso Assumimos que no servidor de demonstração está
significa que as chamadas ao sistema operacional não salvo um arquivo chamado “helloWorld.js”.
ficam bloqueadas mesmo que demorem algum tempo Novamente perguntamos, porque isso é útil? As
para responder. Ao invés de bloquear, é fornecida pessoas na Oracle (slide 10) viram diversos casos de
uma função de callback que será acionada uma vez uso para uma biblioteca. Concordo principalmente
que a chamada terminar, entregando os resultados, com dois deles:
se houver algum. 1. Se temos uma aplicação Node e queremos usar
Há diversas empresas que usam o Node para certas bibliotecas do Java para complementar a API
aplicações sérias, como o Walmart e o Paypal. do Node;
Vejamos um pequeno exemplo de JavaScript que 2. Se queremos trocar para as APIs do JavaScript e
foi adaptado do site do Node: Node, mas precisamos embarcar o código Java legado
em partes ou completamente.
// carrega o módulo ‘http’ (isso é bloqueante) Ambos casos de uso funcionam usando o Avatar.
para tratar requisições http. js e chamando qualquer classe necessária do Java
var http = require(‘http’); através do código JavaScript, que é suportado pelo
Nashorn.
// quando há uma requisição, retornamos ‘Hello, World\n’. Vejamos um exemplo do primeiro uso. O JavaScript
function handleRequest(req, res) { tem atualmente apenas um único tipo para expressar
res.writeHead(200, {‘Content-Type’: ‘text/plain’}); números chamado “number”. Sendo equivalente ao
res.end(‘Hello, World\n’); tipo de precisão do “double” do Java, com as mesmas
} limitações; o number do JavaScript, como o double
do Java não é capaz de expressar tamanho e precisão
// Vamos escutar a porta 1337 do localhost arbitrária, por exemplo para tratar de valores
// e dar um handleRequest quando a chamada voltar. monetários.
// Veja aqui a forma sem bloqueio / assíncrona. No Java podemos usar o BigDecimal, que suporta
http.createServer(handleRequest).listen(1337, ‘127.0.0.1’); exatamente isso. Mas o JavaScript não tem uma
construção equivalente, então podemos acessar a
// registramos no console para garantir classe BigDecimal através do código JavaScript e ter
que a aplicação foi inicializada. o mesmo tratamento seguro de valores monetários.
console.log(‘Get your hello at http://127.0.0.1:1337/’); Vejamos um exemplo de web service que calcula o
percentual de alguma quantia. Primeiro precisamos
Para executar esse código será necessário instalar de uma função que faz o cálculo real:
o Node, salvar o códigos JavaScript no arquivo e
finalmente chamar o Node passando o arquivo como
parâmetro.

eMag | Java: Presente e Futuro 47


var BigDecimal = Java.type(‘java.math.BigDecimal’); … usando o navegador web, obtemos a resposta
correta “7567230000000000006600158.73” que seria
function calculatePercentage(amount, percentage) { impossível de calcular usando apenas o tipo “num-
var result = new BigDecimal(amount).multiply( ber” do JavaScript.
new BigDecimal(percentage)).divide( O segundo caso pode fazer mais sentido quando
new BigDecimal(“100”), 2, decidimos migrar uma aplicação JEE existente para
BigDecimal.ROUND_HALF_EVEN); JavaScript e Node. Nesse caso podemos facilmente
return result.toPlainString(); acessar todos os serviços existentes com o JavaScript.
} Outro caso de uso relacionado, podemos ter uma
nova parte da funcionalidade do servidor construído
No JavaScript não há declaração de tipos, mas fora usando JavaScript e Node que pode se beneficiar dos
isso, o código se parece muito com o código Java, serviços JEE existentes.
como mostrado a seguir: Indo na mesma direção, há também o Projeto Ava-
tar que é baseado no Avatar.js. Os detalhes vão além
public static String calculate(String do escopo desse artigo, mas para ter uma visão rápida
amount, String percentage) { dê uma olhada no anúncio feito pela Oracle. A ideia
BigDecimal result = new BigDecimal(amount).multiply( básica é escrever a aplicação em JavaScript e acessar
new BigDecimal(percentage)).divide( os serviços JEE. O Projeto Avatar vem com uma dis-
new BigDecimal(“100”), 2, tribuição binária combinanda com o Avatar.js mas
BigDecimal.ROUND_HALF_EVEN); precisa do Glassfish para instalar e desenvolver.
return result.toPlainString();
}

Apenas precisamos substituir a função handleRe- O projeto Nashorn aumentou a implementação


quest do Node, como no exemplo anterior, para com- original do Rhino no JDK 6 fornecendo melhorias
pletarmos o código. Como esse: de desempenho para aplicações de execução longa,
por exemplo quando usamos dentro de um servidor
// Carrega o módulo utilitário ‘url’ para converter a url. de aplicações web. O Nashorn integra o Java com
var url = require(‘url’); o JavaScript e permite usar as novas expressões
lambdas do JDK 8. Uma inovação real vem com o
function handleRequest(req, res) { Avatar.js que fornece integração com o Java EE e o
// ‘/calculate’ é o caminho do web service. código JavaScript sendo amplamente compatível com
if (url.parse(req.url).pathname === ‘/calculate’) { o padrão para programação no servidor JavaScript.
var query = url.parse(req.url, true).query; Os exemplos completos, incluindo o binário do
// Quantia e percentual são passados como Avatar.js para Mac OS X, estão disponíveis no Github.
parâmentro de consulta da requisição.
var result = calculatePercentage(query.amount,
query.percentage);
res.writeHead(200, {‘Content-Type’: ‘text/plain’});
res.end(result + ‘\n’);
}
}

Usamos o segundo módulo principal do Node


Sobre o Autor
para processar a URL da requisição para converter os
parâmetros da consulta em quantia e porcentagem.
Após iniciar o servidor, se fizermos uma requisi-
ção como ...
Oliver Zeigermann é consultor de arquitetura e desen-
http://localhost:1337/calculate?amoun- volvimento de software, e Coach em Hamburg, Alema-
t=99700000000000000086958613&percentage=7.59 nha. Atualmente tem se concentrado em usar JavaS-
cript em aplicações corporativas.

48 InfoQ Brasil
JAVA 9 E ALÉM: BRIAN GOETZ E JOHN ROSE
FALAM SOBRE O FUTURO DO JAVA
O InfoQ convidou Brian Goetz (arquiteto da linguagem Java) e John Rose (arquiteto da JVM) para discutir a funcionalidades previstas
para o Java 9 e versões posteriores.

InfoQ: Vocês distinguem entre a reificação de tipos uma classe separada, sem relação entre essas classes. Não é o que
genéricos e a especialização primitiva. Podem falar mais estamos propondo. Mas alguns tipos genéricos como List<int> po-
sobre isso? dem ser representados por uma classe diferente de List<String>.
Ou seja, o mapeamento de tipos em tempo de compilação para
Goetz: Os desenvolvedores não se sentem bem com a remoção classes em tempo de execução pode funcionar de forma diferente,
de informações de tipos (type erasure); têm o sentimento de estar na criação de listas para tipos primitivos e em listas para referência
fazendo alguma coisa errada. Na verdade, o type erasure é útil e de objetos.
aplicar a técnica gera poucos problemas. Por outro lado, o Boxing é Rose: Isso significa que as estruturas equivalentes de tipos de
ineficiente, usa mais memória, enfraquece a localidade e demanda valor que tiveram informação de tipos removida aparecerão no
mais do Garbage Collector. É ótimo que código como ArrayList<T> bytecode.
possa abstrair diversos Ts. Mas o desenvolvedor não deve pagar o Goetz: Dizendo de outra maneira: desenvolvedores que estão
preço do boxing para obter a abstração dos tipos genéricos – quan- usando (raw types) ou <?> para evitar fazer certas decisões, terão
do tudo o que precisa é de um Array de tipos inteiros primitivos. de aprender como fazer corretamente. Assim que tivermos espe-
cialização e valores de tipo (value types), o uso de raw types será
InfoQ.com: E quanto às formas de type erasure em in- cada vez menos aceito. Se você não sabe usar bem tipos genéricos,
terfaces, com perda de informação, como em sobrecargas? chegou a hora de aprender. Já estamos percebemos coisa do gê-
List<String> e List<Map<String, Integer>> seriam tipos nero com os lambdas. Se você consultar o Stack Overflow, vai ver
distintos no Java 10? muitas perguntas do tipo: “por que não consigo fazer isso e aquilo
com um lambda?”. São questões relacionadas ao uso incorreto de
Goetz: List<String> e List<Integer> sempre foram tipos diferen- tipos genéricos, o que faz o sistema de inferência de tipos falhar.
tes, mas esses dois tipos são representados pela mesma classe em
tempo de execução. A remoção de informação de tipos (erasure) InfoQ.com: Falem um pouco sobre a possibilidade de
impede que se descubra se um tipo List foi definido como List<S- Optional ser um tipo “proto-value”
tring> ou um List<Integer> antes de a informação ser removida.
Uma tradução heterogênea completa de tipos genéricos, como Goetz: Havia uma pequena otimização potencial ao migrar um
a usada nos templates do C++, mapearia cada um desses tipos para tipo de referência do Java 8 para um tipo de valor no Java 10. Ba-

eMag | Java: Presente e Futuro 49


sicamente, preparamos o terreno indicando aos desenvolvedores Rose: O Java tem 20 anos de idade e ouvem-se reclamações so-
que não devem depender que certas propriedades (como verifica- bre arrays desde a primeira versão. Estamos convergindo para uma
ção de identidade) sejam verdadeiras para os tipos que podem se API que permita atingir dados unidimensionais (flat data). Estamos
tornar value types no futuro. Sempre que a migração para tipos de chegando perto de iniciar protótipos – que é o objetivo do Projeto
valor se mostrar útil na prática, ela poderá acontecer. Panama. A IBM foi envolvida desde o início; há uma lista de discus-
são especial de que os engenheiros da VM da empresa podem par-
InfoQ.com: Haverá JSRs para os projetos Panama e o ticipar. São necessárias mudanças na linguagem, por exemplo os
Valhalla, ou para alguma tecnologia vinda deles? Quando value types e mudanças em algumas premissas.
saberemos em qual release do Java serão incluídos?
InfoQ.com: A Hazelcast, entre outras empresas, tem
Rose: É sempre melhor iniciar uma JSR quando já se tem ideia pedido por arrays usando índices do tipo long. Isso é pos-
de onde se quer chegar. A criação de JSRs deve acontecer ideal- sível?
mente entre dois momentos: depois de determinar a versão do JDK
e antes de se ter um protótipo bem aceito. Rose: Todas as novas APIs para dados em que estamos traba-
Goetz: Exatamente. Isso é similar com o que aconteceu com os lhando têm índices long.
lambdas, que iniciamos juntamente com o OpenJDK. A JSR foi lan- Goetz: Estamos trabalhando nisso, mas temos que lembrar que
çada assim que definimos os critérios de sucesso para o projeto os com relação a novas funcionalidades há um número muito grande
especialistas que formariam o Expert Group da JSR. de combinações possíveis: em esparsidade, tamanho, leitura e es-
Rose: As JSRs trazem muitos benefícios, mas é necessário um crita ou somente leitura. Os desenvolvedores têm diferentes neces-
bom ponto de partida – especialmente para não acontecer de for- sidades e é necessário priorizar.
marmos uma equipe cedo depois e desperdiçar o tempo dos es- Rose: É verdade. Há muitos graus de liberdade, como em pi-
pecialistas. zzas! Não queremos tratar uma “pizza de cogumelos e cebolas”
Goetz: Temos sorte que agora todos os aspectos legais para como uma combinação completamente diferente de uma “pizza
desenvolver as JSRs no OpenJDK estão resolvidos. Assim podemos com cebolas e pimentas”. Isso nos levaria a uma explosão combi-
desenvolvê-las de forma aberta desde o início. Com relação a re- natória. Queremos, em vez disso, que se possa dizer “escolha várias
leases, acompanhe os repositórios do Valhalla, especialmente as coberturas”. Ainda estamos trabalhando para definir o “cardápio”
pequenas migrações entre os repositórios do JDK9 e JDK 10. a ser oferecido
Um padrão de arquitetura comum é separar os dados gerencia-
InfoQ.com: O que dizem sobre os projetos com novas dos pela aplicação. Usuários têm custos incrementais de gerencia-
abordagens para acesso a dados, como os Packed Objects mento, portanto vão querer gerenciar os dados eles mesmos. Isso
da IBM e o ObjectLayout de Gil Tene? leva a um número grande de bytes formatados pela aplicação, o
que leva diretamente ao acesso nativo a dados.

Sobre os Participantes
Brian Goetz é desenvolvedor profissional há mais
de 20 anos e autor do popular livro ‘Java Concur-
rency in Practice’. Escreveu mais de 75 artigos sobre
desenvolvimento em Java e foi líder da especifica-
ção que trouxe os lambdas para a linguagem (JSR
335). Goetz é o Arquiteto da Linguage Java na Ora-
cle.
John Rose é líder do projeto Da Vinci no OpenJDK.
Liderou a JSR 292, que introduziu no Java o suporte
a invocações dinâmicas e profiling de tipos. Antes
disso, participou da criação dos inner cla

50 InfoQ Brasil
NOVOS HORIZONTES DO JAVA
por Ben Evans, Victor Grazi e Abraham Marín Pérez.
Tradução/Adaptação: Leonardo Galvão, Wellington Pinheiro e Wellington Soares
A renovação da linguagem e plataforma Java está acelerando. Com muitas novas características no horizonte para versão 9 e além, o Java continua
avançando em qualidade, desempenho e facilidade de uso. Conheça nesse artigo uma seleção do que está por vir.

S
Se havia dúvidas que o Java era o padrão de fato para Primeiros anúncios
desenvolvimento no lado servidor, o Java 8 resolveu evolução do Java 9, adaptando várias notícias e artigos do
essa questão. Agora o mundo aguarda ansiosamente InfoQ, Conheça o que está a caminho!
pelo Java 9, atualmente agendado para março de 2017. O Java 9 teve início em agosto de 2014, quandi a Oracle
Há muitas coisas no horizonte para versão 9 e além. O anunciou o primeiro grupo de JEPs para o Java 9 (JEP
projeto Jigsaw pode ser considerado o carro-chefe do Java = Java Enhancement Proposal – ‘Proposta de Aperfeiço-
9; está destinado a trazer programação modular ao mains- amento’).
tream do Java. Depois de anos de negociações e múltiplas Os JEPs fazem parte de um novo processo que permite
JSRs e JEPs, o projeto está assumindo sua forma final. funcionalidades da linguagem e VM do Java para ser ex-
Outras novas funcionalidades do Java 9 são o suporte ploradas sem a necessidade de um processo de especifica-
a HTTP/2 e o REPL, além de um modelo de memória re- ção completo como o atual JSR. Isso permite que o escopo
novado e novas técnicas de garbage collection. O HTTP/2 dos JEPs seja menor e mais focado e que tratem são especí-
trata de problema antigos do suporte enferrujado ao ficos à implementação OpenJDK. JEPs bem sucedidas po-
HTTP no Java atual. dem então ser convertidas em pedidos de padronização
Já o REPL é permite a desenvolvedores testar códigos no JSR ou incluídas em padrões existentes.
interativamente, sem a necessidade de se preocupar com Três novas APIs foram anunciadas inicialmente:
estruturas de classes e compiladores. E o novo coletor de • Process API Updates para interação com processos
lixo Garbage First (também conhecido como G1GC) pro- de sistema operacional não baseados em Java;
mete suportar heaps imensos com o mínimo de interrup- • Um novo HTTP Client que inclui suporte a HTTP/2;
ções. • Uma nova API leve para JSON, que deve ser cons-
A inovações, porém, vão bem além dessa lista. Nas truída com base no suporte a JSON (JSR 353).
seções seguintes compilamos um pequeno histórico da • Há também três novidades voltadas ao desempenho:

eMag | Java: Presente e Futuro 51


• Melhoria em locks de contenção, para aumento de foi anunciado, incluindo o Datagram Transport Layer Se-
desempenho quando múltiplos threads competem curity (DTLS), e uma atualização da ferramenta Javadoc
pelo acesso a objetos; para geração de HTML5.
• Segmentação do cache de código do JIT, para me- As JEPs também indicam que a especialização de tipos
lhor desempenho do compilador Just in Time em primitivos em tipos genéricos (para permitir estruturas
grandes aplicações; como List<int>) não está mais planejada para o JDK9, mas
• Novas melhorias no compilador Java “inteligente”, o sim para o JDK10.
sjavac; essa ferramenta promete compilação parale-
la e compartilhada, entre outras melhorias.
Quanto ao JEP 201 (Código Fonte Modular), ele não era Data final quase definida, com alguns sacrifícios
neste momento o o projeto Jigsaw prometido para versões Em julho de 2016, Mark Reinhold, Arquiteto Chefe da
anteriores do Java – mas sim um trabalho de limpeza no Plataforma Java, sugeriu um método para avaliar coleti-
OpenJDK preparando as bases para a modularidade. vamente o trabalho restante em JEPs inacabadas, e decidir
Esse JEP estabeleceu limites claros para cada módulo se será atrasado o Java 9 ainda mais para acomodar as úl-
ao mesmo tempo que o próprio JDK está sendo construído. tima mudanças – ou se serão retirados JEPs pendentes do
escopo da versão 9. O processo está em andamento, mas
Outras novidades tudo indica que deve haver uma combinação dessas duas
Foi um primeiro passo na direção da modularidade com- estratégias.
pleta, ainda que os módulos não estivessem visíveis ao Por um lado, há uma conjunto fundamental de fun-
desenvolvedor em tempo de execução. cionalidades que dão sentido à nova versão. Para esses,
Em novembro de 2014, a Oracle anunciou outras fun- a data final tem de ser adiada, a fim de incluir as funcio-
cionalidades do Java 9, com destaque para a modularida- nalidades centrais. Por outro lado, Reinhold enfatiza a
de da plataforma. Veja outras mudanças anunciadas: importância de se estabelecer um ritmo previsível para
• Logging unificado na JVM – uma grande revisão novas versões. Ele percebe que funcionalidades não-fun-
no mecanismo interno de notificação de eventos na damentais devem ser removidas do escopo se não forem
JVM, permitindo substituir o atual sistema de log- terminadas a tempo.
ging por um sistema comum e unificado, possibi- Esse raciocínio está alinhado com o processo proposto
litando que diversos componentes compartilhem o para seleção de JEPs. Desse modo, espera-se que os líderes
mecanismo de logging; das JEPs solicitem uma prorrogação do prazo, indicando a
• Remoção de combinações de GC obsoletas – a re- data estimada de entrega – ou comuniquem a sua “saída”
moção das combinações: DefNew + CMS, ParNew do Java 9. No caso de prorrogação, um processo de revisão
+ SerialOld e Incremental CMS. Estas haviam sido irá determinar se a extensão será concedida ou não.
marcadas como obsoletas no Java 8; Atualmente 11 JEPs estão em análise – de um total de
• Mais controle sobre o compilador – melhoria no 82.
controle sobre o compilador Hotspot JIT, permitin- Entre os JEPs em risco de saírem do Java 9, a julgar pelo
do adicionar opções para cada método a ser compi- estado do issue tracker no momento de escrita, dez soli-
lado e alterar as opcões em runtime. Por exemplo, citaram prorrogação do prazo (com sete já aprovados). A
adicionar diretivas para habilitar ou desabilitar data de entrega revista para estas JEPs é 1 de setembro,
uma otimização específica para determinado méto- o que significa atraso de cerca de três meses – levando o
do, remover a opção de o método ser inline ou até lançamento do Java 9 para junho de 2017.
mesmo instalar uma diretiva durante a execução e Quatro JEPs seriam removidos do release para evitar
verificar seu resultado; novos atrasos:
• Project Coin atualizado – Ajustes em alguns deta- • JEP 110 Cliente HTTP / 2
lhes originados no Java 7 (Project Coin) que trouxe • JEP 227 Depreciação melhorada
mudanças na linguagem. Serão permitidos @Safe- • JEP 282 JLINK
Vargs em métodos privados, o operador diamond • JEP 284 Novo sistema de builds do HotSpot
com inner classes, entre outras mudanças. Embora ainda não haja definição final, as decisões re-
Novidades incluem também o término do projeto centes tendem a estabelecer a forma definitiva do Java 9.
de remoção de warnings e uma limpeza no gerenciador Porém, se os JEPs acima forem mesmo removidos, uma
de importação. Ao importar classes obsoletas, não serão análise mais aprofundada será necessária para ava-
mais disparados alertas. Além disso, alguns problemas liar seu impacto, especialmente com relação ao JEP 282
antigos na resolução de tipos no javac serão corrigidos. (JLINK), que faz parte do sistema de módulos, central à
O suporte a algumas tecnologias modernas também nova versão do Java.

52 InfoQ Brasil
eMag | Java: Presente e Futuro 53