Professional Documents
Culture Documents
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
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.
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.
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-
• 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.
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)
8 InfoQ Brasil
Um exemplo de saída:
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.
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.
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.)
Sobre o Autor
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
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.
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.
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
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
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-
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.
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
“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
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
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-
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
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.
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.
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
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.
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
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
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”).
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.
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-
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:
52 InfoQ Brasil
eMag | Java: Presente e Futuro 53