O uso do JavaScript tem crescido
consistentemente nestes últimos anos, tanto que a linguagem não apenas figura,
mas aparece bem posicionada nos mais conhecidos rankings de utilização de
linguagens de programação (TIOBE Index, GitHub PYPL, RedMonk, IEEE Spectrum,
etc).
Não é preciso justificar porque o
JavaScript é importante. Introduzido em 1995 por Brendan Eich, sob o nome
original Mocha, acabou sendo renomeado para JavaScript para aproveitar o
sucesso inicial do Java, lançado no mesmo ano. Sua característica mais marcante
é trazer interatividade a páginas HTML, sendo executada pelo browser, ou seja,
operando do lado do cliente.
Com o passar do tempo e apesar das críticas
de muitos programadores, o JavaScript evoluiu e hoje permite o controle
sofisticado do conteúdo de páginas web, permitindo a troca de estilos, a
ocultação/exibição de elementos, a realização de validações e outras operações
mais complexas.
A partir de 2005, com o advento do AJAX (Asynchronous
JavaScript and XML), ocorre seu renascimento do JavaScript, e surgem frameworks
importantes como Prototype, JQuery, Dojo e Mootools, assim como esforço
consistente para sua padronização (ECMAScript 3.1 a 5.1). Hoje o JavaSript é uma
linguagem de programação amplamente utilizada.
Nashorn
O Nashorn é uma implementação de um
mecanismo (ou motor) de execução para linguagem de programação JavaScript
integrado a plataforma Java, disponível a partir da versão 8, compatível com a
especificação ECMAScript 262 v5.1, que se beneficia da enorme quantidade de
ferramentas e bibliotecas disponíveis para JavaScript, possibilitando sua
integração com a plataforma Java e, portanto, conjugando as vantagens destes
dois mundos.
Até a versão 7 do Java, o mecanismo de
execução padrão do JavaScript disponível no Java era o Rhino, baseado num
projeto de mesmo nome voltado para os navegadores Mozilla. Apenas como
curiosidade, a palavra nashorn significa rinoceronte em alemão e também
denominou um tanque de guerra conhecido como destruidor de tanques.
O mecanismo de execução Nashorn é acessível
por meio da API javax.script e da ferramenta de linha de comando jjs,
suportando a execução de scripts escritos em JavaScript embutidos em programas
Java, incluindo aplicações JavaFX.
A sintaxe da linguagem JavaScript é
bastante semelhante a do Java e o acesso a elementos Java a partir do
JavaScript, como arrays e objetos, é praticamente idêntico, de modo que o Java
tem acesso a valores e elementos do JavaScript e vice-versa.
Programa Java executa script JavaScript
O exemplo que segue (classe Nashorn01) mostra um programa de
console Java que utiliza o Nashorn para executar um comando JavaScript.
import javax.script.*;
public class Nashorn01 {
public
static void main(String[] arg) {
// Obtem acesso ao mecanismo de
execucao JS Nashorn
final
ScriptEngine nashorn =
new ScriptEngineManager().getEngineByName("nashorn");
try
{
// Script JS pode ser hardcoded ou
// obtido por outros meios (p.e., arquivo)
String script = "print('Hello
World!')";
// Execucao do script JS
nashorn.eval(script);
} catch (final
ScriptException se) {
System.out.println(se);
}
}
}
Na classe Nashorn01, uma instância de
ScriptEngineManager é criada para que, por meio de seu método
getEngineByName(String) e o nome "nashorn", se possa obter uma
instância do mecanismo de execução correspondente ao Nashorn. Com o objeto ScriptEngine
obtido é possível executar-se diretivas JavaScript individuais ou scripts
inteiros com uso do método eval(String). É necessário monitorar tal avaliação
com um try/catch.
Retorno de valor do script JavaScript para Java
Neste outro exemplo (classe Nashhor02), o script é lido de um
arquivo cujo nome é fornecido como argumento para o programa. O mecanismo de
execução Nashorn é obtido da mesma maneira, mas sua utilização é um pouco
diferente.
import java.io.*;
import javax.script.*;
public class Nashorn02 {
public static void
main(String[] arg) {
// Script obtido do arquivo
indicado como argumento
StringBuffer script = new
StringBuffer();
try (BufferedReader br =
new BufferedReader(new FileReader(arg[0]))) {
String line = null;
while (
(line=br.readLine()) != null) {
script.append(line);
script.append("\n");
}
} catch (Exception exc) {
System.out.println("Erro:
" + exc);
System.exit(-1);
}
try {
// Obtem acesso ao
mec. execucao JS Nashorn
final ScriptEngine
nashorn =
= new
ScriptEngineManager().getEngineByName("nashorn");
// Execucao do script
JS
Object returnValue =
nashorn.eval(script.toString());
System.out.println("Java:
" + returnValue);
} catch (final
ScriptException se) {
System.out.println(se);
}
}
}
O resultado do método eval(String) é
atribuído a uma variável Java do tipo Object, de modo que é possível transferir
um resultado do script Javascript para o programa Java. Basta para isso que a
variável cujo valor deseja-se retornar seja indicada como uma diretiva ao final
do script, como no script simples que segue, onde a variável f tem seu valor
retornado para o programa Java.
// teste01.js
var c = 33;
print('JavaScript: ' + c);
var f = c*9.0/5.0 + 32.0;
print('JavaScript: ' + f);
f; // retorno de valor
O valor retornado pode ser convertido em
outros tipos por meio de operações de coerção, no caso, como o resultado é do
tipo double, poderia ser aplicado:
double resultValue = (Double) nashorn.eval(script.toString);
Passagem de valores entre programa Java e script JavaScript
Também é possível passar valores do programa
Java para o script Javascript com o uso do método put(String, Object)
disponível na classe ScriptEngine. que define uma variável com o valor indicado
(ou global variable binding). O
exemplo que segue transfere dois valores do programa Java para o script, que
soma tais valores, retornando tal resultado para o programa, usando o método
get(String).
import javax.script.*;
public class Nashorn03 {
public static void
main(String[] arg) {
// Obtem acesso ao
mecanismo de execucao JS Nashorn
final ScriptEngine nashorn
=
new
ScriptEngineManager().getEngineByName("nashorn");
// Script JS hardcoded
String script =
"var c
= a + 2*b;\nprint('JavaScript: ' + c);";
try {
// Transferência de
valores: programa -> script
nashorn.put("a", 123);
nashorn.put("b", 0.456);
// Execucao do script
JS
nashorn.eval(script);
// Transferência dos
resultados: script -> programa
double result =
(Double) nashorn.get("c");
System.out.println("Java:
" + result);
} catch (final
ScriptException se) {
System.out.println(se);
}
}
}
Script JavaScript que utiliza classes Java
Outra possibilidade interessante decorrente
da integração do mecanismo de execução Nashorn na JVM é o compartilhamento da API
Java por parte dos script JavaScript. Um objeto Java pode ser instanciado de
duas formas:
- Instanciação direta:var lista = new java.util.ArrayList();
- Instanciação indireta:var AL = java.util.ArrayList;
var lista = new AL;
As duas formas produzem o mesmo efeito. O
que muda é a quantidade de código digitado: a instanciação direta é mais
verborrágica, portanto, mais longa, no entanto, clara e direta; a instanciação
indireta permite instanciar objetos com menos código, embora possa ser menos
clara conforme os apelidos usados para as classes efetivamente usadas.
O uso dos objetos é como no Java, tal como
mostrado no exemplo que segue, onde um script JavaScript utilizar uma tabela de
hashing, um array elástico e um buffer para String para manipular uma lista de
linguagens de programação e seus inventores.
// teste02.js
var HM = java.util.HashMap;
// instanciação indireta
var map = new HM();
var list = new java.util.ArrayList(); //
instanciação diretas
var buffer = new
java.lang.StringBuffer("|");
map.put("JavaScript","Brendan
Eich");
map.put("Java","James
Gosling");
map.put("C#","Anders
Hejlsberg");
map.put("Pascal","Niklaus
Wirth");
for (var key in map) {
print('key: ' + key); list.add(key); }
for each (var value in map) {
print('value: ' + value);
buffer.append(value);
buffer.append("|");
}
for each (var key in list)
print('{ ' + key + ', ' + map.get(key) + ' }');
print(buffer.toString());
list // retorno de
objeto
Este script, salvo sob o nome de
teste02.js, é executado com uso da classe/exemplo Nashorn02, dada
anteriormente.
Console JavaScript
Junto com o JDK 8 existe um console
JavaScript (uma ferramenta de linha de comando) denominada jjs que provê acesso
direto ao mecanismo de execução Nashorn, comportando-se como um REPL (Read-Evaluate-Print-Loop),
ou seja, um console que lê comandos JavaScript, executando-os e imprimindo os
resultados no próprio console, interativa e repetidamente, o que é muito
conveniente para testar comandos, executar pequenas rotinas e testes, incluindo
experimentar elementos Java e JavaScript sem a necessidade de escrever
programas completos.
Para acioná-la basta digitar 'jjs'
(considerando que a variável de ambiente path está corretamente configurada
para incluir o diretório <java_install>/bin). Considere as várias
sequências que seguem de comandos que podem ser digitados no jjs. A primeira
define variáveis e exibe o resultado de uma expressão:
jjs> var a = 1.5;
jjs> var b = -3;
jjs> print (2*a -
0.5*b);
4.5
Agora a definição e a
exibição de um array simples:
jjs> var array =
[];
jjs> array[0] =
'Peter';
Peter
jjs> array[1] =
2017;
2017
jjs> array
Peter,2017
jjs>
array.length
2
jjs> for(var i=0;
i<array.length; i++) print(array[i]);
Peter
2017
jjs> for each (var
v in array) print(v);
Peter
2017
Para encerrar o jjs
deve ser fornecido quit().
Objetos Java podem ser
instanciados e utilizados, como segue:
jjs> var list = new
java.util.ArrayList();
jjs>
list.add('Peter');
true
jjs>
list.add('Jandl');
true
jjs> list
[Peter, Jandl]
jjs> list.size();
2
jjs> var i = 10;
jjs> for each (var
v in list) { print(i + ':' + v); i = i + 10; }
10:Peter
20:Jandl
30
Características
avançadas do Java, como expressões lambda e streams também podem ser usadas
(com alguns cuidados). Considerando o ArrayList list definido acima, poderia
ser escrito:
jjs> list .stream()
.filter(function(s) s.startsWith('J')) .forEach(function(s) print(s));
Jandl
null
Neste fragmento devem
ser observados alguns aspectos:
- onde é possível usar
uma expressão lambdas no Java, emprega-se uma função JavaScript; de maneira que
o lambda Java
"s -> s.startsWith('J')"
torna-se
"function(s) s.startsWith('J')"; - o valor 'Jandl' é o valor resultante da exibição dos elementos filtrados do stream obtido da coleção list;
- como o método forEach(Consumer) é terminal, seu valor de retorno é void, assim sua avaliação pelo jjs retorna null.
O modo interativo do jjs é bastante útil
para experiências e testes diversos. Mas não é conveniente quando desejamos
executar (ou repetir) uma sequência conhecida (ou longa) de comandos. Um
conjunto de comandos JavaScript, com ou sem uso de elementos do Java, pode ser
salvo num arquivo de script, o qual pode ser executado pelo jjs em seu modo de
interpretação (ou batch). Para executar o script teste02.js basta escrever:
> jjs –scripting teste02.js
Conclusões
Dada a importância atual do JavaScript, sua
utilização integrada à plataforma Java é bastante interessante. Assim o Nashorn
é bastante útil ao permitir que programas Java utilizem funcionalidades
JavaScript; que programas JavaScript compartilhem elementos do Java; que o
desenvolvedor disponha de um console JavaScript para testes diversos, execução
de tarefas rápidas, prototipação, teste de características do Java e construção
de scripts usando Java e JavaScript combinados.
Atualmente o Nashorn (Java 8) suporta
completamente o padrão ECMAScript 5.1, além de algumas extensões. Pretende-se
que com o Java 9 o Nashorn seja atualizado para suportar o ECMAScript 6. Tudo
muito útil e conveniente.
Para Saber Mais
- Oracle Nashorn: A Next-Generation JavaScript Engine for the JVMhttp://www.oracle.com/technetwork/articles/java/jf14-nashorn-2126515.html
- Nashorn: Combinando o
poder do Java e JavaScript no JDK 8
https://www.infoq.com/br/articles/nashorn - Java 8 Nashorn
Tutorial
http://winterbe.com/posts/2014/04/05/java8-nashorn-tutorial/ - Nashorn: Desenvolvendo
JavaScript na JVM
http://www.devmedia.com.br/nashorn-desenvolvendo-javascript-na-jvm/31033 - Nashorn and Lambda,
What the Hey!
https://blogs.oracle.com/nashorn/entry/nashorn_and_lambda_what_the
Nenhum comentário:
Postar um comentário