Optional
Objetivo
• Esta apresentação explora as principais novidades do
Java 8 (que foi lançado em março)
• O foco será nas mudanças na sintaxe (lambdas), APIs
(streams, data e hora) e ferramentas (nashorn)
• Não serão discutidas nesta apresentação mudanças
na JVM, JavaFX, runtime (Compact profiles) segurança
(JCA) nem monitoração (JMC)
Conteúdo
• Parte I - Mudanças na sintaxe da linguagem
• 1. Expressões lambda e referências para métodos
• 2. Nova sintaxe para interfaces
• Parte II - Novas APIs
• 3. Data e hora (java.time)
• 4. Interfaces funcionais (java.util.function)
• 5. API funcional (java.util.stream)
• 5. Paralelismo (ForkJoinPool.common())
• 6. API reativa (java.util.concurrent.CompletableFuture)
• Parte III - Ferramentas
• 7. JavaScript engine API e ferramenta jjs (Nashorn)
1. Expressões lambda
• Uma expressão lambda é uma função anônima
• É abstração de uma operação, tratada como se fosse
dados, permitindo que seja atribuída a variáveis e retornada/
passada de/para métodos
• Tem origem no cálculo lambda (Alonzo Church, 1936) e é
usado em programação desde Lisp (1958)
• Faz parte de várias linguagens populares: JavaScript, Scala,
C#, Go, Swift, Smalltalk, Python
Programação funcional
• Lambdas são uma abstração fundamental em linguagens
funcionais
• Em orientação a objetos, o estado de objetos é modificado
por operações representadas por seus métodos
• Na programação funcional, operações são representadas por
funções entre objetos imutáveis
• Embora não tenha sido concebida como linguagem funcional,
é possível programar em Java usando o paradigma funcional
• AAPI de streams facilita a programação funcional em Java 8
Métodos anônimos em Java
• Desde Java 1.2 pode-se implementar interfaces anônimas
Runnable tarefa = new Runnable() {
@Override
public void run() {
System.out.println("Hello!");
}
}
• Java 8 vai mais longe com métodos anônimos (lambdas)
Runnable tarefa = () -> { System.out.println("Hello!"); }
• As chaves são opcionais neste caso:
Runnable tarefa = () -> System.out.println("Hello!");
Sintaxe de expressões lambda
• Novo operador -> (seta) separa parâmetros e expressão
• Variáveis usadas no bloco da expressão lambda devem ser
efetivamente finais (imutáveis)
• Parenteses: obrigatórios se há mais de um parâmetro ou nenhum:
• p -> p/2; // mesmo que (p) -> p/2
• () -> 3; // parênteses necessários
• (a,b) -> a+b; // parênteses necessários
• Declarar tipo dos parâmetros é opcional (se for possível inferir)
• int r = p -> p/2; // Implícito: (int p) -> p/2;
• Chaves e a instrução return: opcionais se apenas uma instrução
• int r = (a,b) -> a+b; // (int a, int b) -> { return a+b;}
Referências de métodos
• O operador :: declara referências para métodos e construtores
• Há quatro tipos
• Classe::metodoEstatico // referência para metodo estatico
• Classe::metodoDeInstancia // ref. para método de um objeto qualquer
• objeto::metodoDeInstancia // ref. para método de um objeto específico
• Classe::new // referência para construtor
• Exemplos
System.out::println Comparator::compare HashSet<Integer>::new
• Uma referência pode substituir uma expressão lambda; os argumentos
são obtidos por inferência (as duas formas abaixo são equivalentes)
• Consumer<String> f1 = s -> System.out.println(s);
• Consumer<String> f2 = System.out::println; interface	Consumer<T>	{	
				void	accept(T	t);	
}
Usará	parâmetro	T	do	
método	por	inferência
2. Sintaxe para interfaces
• Interfaces, a partir de Java 8, podem conter métodos com
implementações, desde que sejam
• Estáticos (com modificador static)
• Default (com novo modificador default)
interface Template {
default String transform(String s) {
return tag(s);
}
static String tag(String s) {
return "<tag>"+s+"</tag>";
}
}
Upper u = new Upper();
Plain p = new Plain();
System.out.println(Template.tag("A"));
System.out.println(u.transform("B"));
System.out.println(p.transform("C"));
class Plain implements Template {
@Override
public String transform(String s) {
return s;
}
}
class Upper implements Template {}
<tag>A</tag>
<tag>B</tag>
C
Métodos default
• Métodos default não precisam ser sobrepostos
• Conflito pode haver se uma classe implementa duas interfaces com
métodos default iguais
• Neste caso é necessário sobrepor o método escolhendo qual
implementação usar
interface A {
default void m() { System.out.println("A"); }
}
interface B {
default void m() { System.out.println("B"); }
}
class C implements A, B {
public void m() {
B.super.m(); // escolhendo implementação B
}
}
3. Nova API de datas
• Cinco pacotes (java.time + 4 subpacotes) com novas abstrações
para intervalos, períodos, datas, meses, eras, anos, unidades,
fusos horários, formatação, etc.
• Principais abstrações estão no pacote raiz java.time
• LocalDate, LocalTime, LocalDateTime
• ZoneId, ZonedDateTime
• OffsetDateTime, OffsetTime, ZoneOffset
• Clock, Duration, Instant, Period
• Month, Year, YearMonth, MonthDay, DayOfWeek
• Objetos são criados com factory methods
Data e Hora
• LocalDate, LocalTime e LocalDateTime representam data ISO
8601 (calendário Gregoriano)
LocalDate date1 = LocalDate.now();
System.out.println(date1);
int day = date1.getDayOfMonth();
System.out.println(day);
LocalDate date2 = LocalDate.parse("2014-08-20");
System.out.println(date2);
LocalDateTime dt = date2.atTime(13, 59);
System.out.println(dt);
LocalTime time = dt.toLocalTime();
System.out.println(time);
LocalTime tonight = time.plusHours(8);
System.out.println(tonight);
LocalDate someDay = LocalDate.of(1995,5,1);
System.out.println(someDay);
2014-08-16
16
2014-08-20
2014-08-20T13:59
13:59
21:59
1995-05-01
Formatação e parsing
• Métodos toString() default utilizam formatações padrão sem a
necessidade de usar formatadores
• É possível personalizar os formatos para formatação e parsing
usando DateTimeFormatter.ofPattern()
DateTimeFormatter formato1 =
DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
DateTimeFormatter formato2 =
DateTimeFormatter.ofPattern("MMMM d, yyyy hh:mm a");
	 	
LocalDateTime ldt = LocalDateTime.parse("20/08/2014 13:59", formato1);
System.out.println(ldt);
String formatted = ldt.format(formato2);
System.out.println(formatted);
2014-08-20T13:59
August 20, 2014 01:59 PM
Duração e período
• Instant representa um instante qualquer
Instant agora = Instant.now(); // 2014-08-16T14:44:07.989809Z
Instant depois = agora.plusSeconds(30); // 2014-08-16T14:44:37.989809Z
• Duration representa uma duração de tempo (30 segundos)
Duration duracao = Duration.between(agora, depois); // PT30S
• Period representa um intervalo entre duas datas (4 meses, 16 dias)
Period periodo = 

Period.between(LocalDate.now(), LocalDate.of(2015, 1, 1)); // P4M16D
• Clock permite relógios alternativos (com offset, com resolução de minutos, etc)
Clock relogioSistema = Clock.systemUTC(); // Default SystemClock[Z]
Clock tictac = 

Clock.tickMinutes(ZoneId.systemDefault()); // Conta apenas minutos
Instant start = tictac.instant(); // 2014-08-16T17:54:00Z
Duration elapsed =
Duration.between(start, start.plusSeconds(126)); // PT2M6S
Interface comum
• Prefixos comuns a métodos estáticos em classes do pacote
• of - método de fábrica: ZoneId zone = ZoneId.of("GMT");
• parse - método de fábrica: LocalDate d = LocalDate.parse("2014-08-19");
• Prefixos comuns a métodos de instância
• get - retorna o valor de algo: int dia = dateTime.getDayOfMonth();
• is - retorna true ou false: boolean bissexto = year.isLeap();
• with - retorna uma cópia modificada: Clock fuso2 = fuso1.withZone(zone);
• plus - adiciona uma quantidade: Period p2 = p1.plusDays(5);
• minus - subtrai uma quantidade: Instant s2 = s2.minusSeconds(30);
• to - converte objeto em outro tipo: int segundos = localTime.toSecondOfDay();
• at - combina objeto com outro: LocalDate data = monthDay.atYear(2014);
4. Interfaces funcionais
• Interface funcional: interface com um método abstrato
• Se houver outros métodos devem ser static ou default
• Podem ser implementadas usando expressões lambda!
• Java 8 introduziu a anotação @FunctionalInterface para
identificar interfaces funcionais em tempo de compilação
• Haverá erro de compilação se interface não for funcional
• O uso de interfaces funcionais em lambdas permite alto grau de
reuso: lambdas ignoram tipos recebidos/retornados
• O pacote java.util.function contém uma coleção de interfaces
padrão para reuso
java.util.function
• 43 interfaces genéricas de propósito geral
• Principais interfaces
• Predicate<T>: Recebe (T); Retorna boolean
• BiPredicate<T,U>: Recebe (T,U); Retorna boolean
• Consumer<T>: Recebe (T); Retorna void
• Supplier<T>: Recebe (); Retorna T
• Function<T,R>: Recebe (T); Retorna R
• BiFunction<T,U,R>: Recebe (T,U); Retorna R
• UnaryOperator<T>: Recebe (T); Retorna T
• BinaryOperator<T, T>: Recebe (T, T); Retorna T
Uso de interfaces funcionais
• O nome do método da interface funcional é irrelevante para criar
expressões lambda, já que é anônimo; tipos também são irrelevantes
• O mais importante são: quantidade de argumentos recebidos e
se retorna ou não algum valor
• Uma expressão usando Supplier<T> com T = String
• Uma expressão usando Function<Integer,String>
• Uma expressão usando BiFunction<T, U, R>
String produto = () -> "Hello!";
String resultado = (a,b) -> a + b; // concatena ou soma
Integer tamanho = s -> s.length(); // recebe String, retorna Integer
Métodos que recebem lambdas
• Um método que recebe uma expressão lambda declara
receber uma interface funcional
• Pode-se implementar uma função anônima e passá-la como
argumento, da mesma forma como são passados os dados
public Integer calcular(Function<Integer> funcao,
Integer operando) {
return funcao.apply(operando);
}
System.out.println( calcular( n -> n * n, 4);
System.out.println( calcular( n -> n / 2, 16);
5. Streams
• A classe java.util.stream.Stream fornece uma API para
programação funcional baseado na concatenação de operações lazy
processadas quando uma operação terminal é chamada
• Um Stream conduz elementos de uma fonte através de uma pipeline
de operações, produzindo um resultado sem modificar a fonte
• Elementos são processados uma única vez (o stream é consumido)
• Streams podem ser infinitos (operações intermediárias podem limitar
os dados durante o processamento)
• Streams podem ser criados/obtidos de várias formas
Como criar um Stream
• Um stream pode ser criado a partir de métodos de fábrica:
generate(), iterate(), of(), etc.
Stream<String> letras = Stream.of("X", "T", "S", "P");
Stream<Integer> infinito = 

Stream.generate(()-> new Random().nextInt(100));
• É mais comum criar um stream a partir de uma coleção usando o
método stream() ou parallelStream()
List<Integer> colecao = new ArrayList(); // ...
Stream<Integer> colecao.stream();
Stream<Integer> colecao.parallelStream(); // paralelismo
• Um stream pode ser transformado via operações intermediárias
(lazy) e uma operação terminal (eager - que encerra o stream)
Operações de um stream
• As operações intermediárias (lazy) são executadas apenas depois
que o stream é terminado (puxando os dados: método "pull")
• Após uma operação terminal o stream não pode ser reusado
• As operações recebem interfaces funcionais
• Algumas operações. Operações intermediárias retornam Stream:
• filter(Predicate<T>): intermediária
• map(Function<T,U>): intermediária
• flatMap(Function<T,Stream<R>>): intermediária
• reduce(BinaryOperator<T>): terminal
• forEach(Consumer<T>): terminal
• collect(Collector<T,A,R>): terminal
Outras	operações	terminais:	
min(),	max(),	count(),	etc.	
Outras	intermediárias:	
skip(),	peek(),	distinct(),	etc.
Filter
• A operação intermediária filter(Predicate<T>) remove
do stream elementos que não combinam com a função
List<Integer> numbers =
Arrays.asList(new Integer[] {4,1,9,6,8,3,5});
numbers.stream()
	 	 .filter(n -> n > 5)
	 	 .forEach(System.out::println);
Imprime	9	
6	
8
Map
• A operação intermediária map(Function<T,U>)
recebe uma função que realiza uma transformação no
stream (e pode converter um tipo em outro):
List<Integer> numbers =
Arrays.asList(new Integer[] {4,1,9,6,8,3,5});
numbers.stream()
	 	 .filter(n -> n > 5)
	 	 .map(n -> n * n)
.forEach(System.out::println);
Imprime	81	
36	
64
ForEach
• O método forEach(Consumer<T>) foi adicionado em Iterable
e está disponível para qualquer implementação (ex: Collection):
list.forEach(System.out::println);
• Stream também implementa Iterable e pode chamar forEach():
Stream<Integer> numeros = Stream.of(1,2,3,4);
numeros.map(s->s*2).forEach(System.out::println);
• ForEach é uma operação terminal (depois de chamada, puxa
a execução do stream não permitindo novos métodos):
numeros.filter(n->n<3); // exceção (stream encerrado)
Reduce
• reduce(BinaryOperator<T>) é uma operação terminal que retorna
resultado da operação de combinação sobre valores acumulados
• Há três diferentes versões de reduce (com 1, 2 ou 3 args)
• O resultado pode ser do mesmo tipo (T), outro tipo ou
Optional<T> (objeto que encapsula T ou null)
List<Integer> numbers =
Arrays.asList(new Integer[] {4,1,9,6,8,3,5});
Optional<Integer> resultado = numbers.stream()
	 	 .filter(n -> n > 5)
	 	 .map(n -> n * n)
.reduce((acum, oper) -> a+b);
int soma = resultado.get(); // 181 (81+36+64)
Collect
• collect(Collector<T,A,R>) é uma operação terminal que executa uma
redução mutável nos elementos do stream. O coletor constrói o
resultado usando funções de acumulação e combinação.
• collect() pode ser usado para reduzir um stream a uma coleção
• Classe utilitária Collectors contém vários algoritmos implementados
(toList(), groupingBy(), etc.)
Map<String, List<Movie>> directors = movieList.stream()
	 .collect(Collectors.groupingBy(Movie::getDirector));
List<String> titles = movieList.stream()
	 	 	 	 .map(movie -> movie.getTitle() +
	 	 	 	 " (" +movie.getDirector()+ ")")
	 	 	 	 .collect(Collectors.toList());
FlatMap
• flatMap(Function<T,Stream<R>>) é uma operação
intermediária que "achata" um stream de streams
List<String> titlesAndDirectors =
movieList.stream()
	 	 .flatMap(movie ->
Stream.of(movie.getTitle(),
	 	 	 	 	 	 	 movie.getDirector()))
	 	 .collect(Collectors.toList());
Exceções e valores nulos
• Streams não podem deixar escapar exceções checadas
• É preciso capturar a exceção
• Pode-se lançar uma exceção de runtime
• Ideal é devolver um objeto comum que contenha informações
que permitam lidar com o problema
• Objetos Optional podem ser usados para lidar com valores nulos
public Optional<Integer> transformar(Integer valor) {
try {
// operações sobre valor
return Optional.of(resultado);
} catch (Excecao e) {
return Optional.empty();
}
} int valor = 123;
Optional<Integer> op = transformar(valor);
Integer resultado = op.orElse(valor);
Retorna	resultado	ou	
123	(se	ocorrer	exceção	
e	Optional	estiver	vazio)
Streams de primitivos
• java.util.stream também contém um conjunto de Streams de primitivos
como DoubleStream, IntStream e LongStream
• Streams comuns podem ser convertidos em streams de primitivos:
mapToInt(), mapToDouble(), etc.
• IntStream stream = lista.stream().mapToInt(n->n);
• Possuem métodos especiais para manipular de primitivos e obter estatísticas
IntSummaryStatistics example =
	 Stream.of(9,4,8,2,15,82,91,77,53,27,13)
	 .mapToInt(n->n).summaryStatistics();
System.out.printf("Count: %d, Max: %d, Min: %d, Avg: %f, Sum: %d",
	 example.getCount(), example.getMax(), example.getMin(),
example.getAverage(), example.getSum());
6. Paralelismo
• O Java 8 introduziu um ForkJoinPool comum para uso em
operações paralelas
• Forma recomendada de uso (new ForkJoinPool() passa
a ser um anti-pattern)
• Configurável via propriedades do sistema
• Pool default para streams paralelos e operações
assíncronas com CompletableFuture
• Para obter uma referência ao pool
• ForkJoinTasks podem ser chamadas sem informar um pool
ForkJoinPool poolComum = ForkJoinPool.common();
task.invoke(); // em vez de pool.invoke(task) usa poolComum
7. CompletableFuture
• Uma API para programação reativa similar à API de streams
(mas baseada em "push" - o oposto da API de streams, que é
baseada em "pull")
• Objetos Future que podem ser concatenados em série
• Contém 36 métodos que executam tarefas assíncronas e
retornam CompletableFuture: recebem interfaces funcionais
• Cada CompletionStage executa um estágio da tarefa
CompletionStage
CompletionStage
CompletionStage CompletableFuture
CompletionStageFuture
Como criar um CompletableFuture
• Usando o construtor default
CompletableFuture<Integer> future = 

new CompletableFuture<>();
future.complete(5);
• Usando métodos de fábrica com Runnable ou Supplier<V>
CompletableFuture<Void> cf1 = 

CompletableFuture.runAsync(() -> {

System.out.print("Etapa assíncrona");

});
CompletableFuture<String> cf2 = 

CompletableFuture.supplyAsync(() -> {

return "Etapa assíncrona";

});
Concatenação de estágios
• Estágios seguintes podem processar dados do estágio anterior
(com tarefas Consumer<T>, Function<T,R> e Runnable)
• Tarefas podem rodar em threads novos (disparados pelo
ForkJoinPool comum) ou escolher um executor próprio
• Há métodos para combinar múltiplos estágios anteriores
CompletableFuture.supplyAsync(() -> event.get() )
.thenApply( x -> x * x )
.thenAccept ( x -> System.out.println(x) )
.thenRun( () -> System.out.println("Done!") );
8. Nashorn
• JavaScript engine (javax.script.ScriptEngine) que permite embutir
JavaScript dentro de aplicações Java e vice-versa
• Código Java pode executar JavaScript e vice-versa e compartilhar
dados e operações
• Mapeamento automático entre linguagens: tipos são convertidos
automaticamente, getters/setters acessíveis como propriedades
JSON, coleções Java são tratadas como arrays JavaScript
• Também inclui uma ferramenta de linha de comando jjs
• Interpretador para programação interativa (REPL)
• Permite escrever código JavaScript usando classes e objetos Java
Chamando JavaScript
final ScriptEngineManager factory =
new ScriptEngineManager();
final ScriptEngine engine =
factory.getEngineByName("nashorn");
	
try {
engine.eval("print('JavaScript hello!');");
} catch (ScriptException e) {
e.printStackTrace();
}
• É necessário obter uma instância de javax.script.ScriptEngine
• Método eval() executa código JavaScript contido em String
JavaScript hello!
OUTPUT
Chamando função externa
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("nashorn");
	
try {
engine.eval(new FileReader("target/classes/test.js"));
Invocable inv = (Invocable)engine;
inv.invokeFunction("printText", "Something");
} catch (ScriptException | FileNotFoundException |
NoSuchMethodException e){ ... }
• eval() pode carregar um script externo
• Invokable.invokeFunction() chama função JavaScript
existente no script carregado
function printText(text) {
	 print("JavaScript prints: " + text);
}
test.js
JavaScript prints: Something
OUTPUT
Acessando objeto (JSON)
final ScriptEngineManager factory =
new ScriptEngineManager();
final ScriptEngine engine =
factory.getEngineByName("nashorn");
try {
ScriptObjectMirror mirror = (ScriptObjectMirror)
engine.eval(new FileReader("target/classes/movie.js"));
System.out.println(mirror.getMember("title"));
System.out.println(mirror.getMember("director"));
System.out.println(mirror.getMember("year"));
} catch (ScriptException |
FileNotFoundException |
NoSuchMethodException e) {
e.printStackTrace();
}
var movie = {
	 "title" : "The Shining",
	 "director" : "Kubrick",
	 "year" : 1980
}
movie;
movie.js
The Shining
Kubrick
1980
OUTPUT
Chamando Java de JavaScript
• Função Java.type("pacote.Class") carrega tipos Java e permite usá-los em
JavaScript
var ArrayList = Java.type("java.util.ArrayList");
var defaultSizeArrayList = new ArrayList;
var customSizeArrayList = new ArrayList(16);
– Pacotes e classes podem ser importados com importPackage() e importClass()
(exemplos do tutorial da Oracle [8]):
load("nashorn:mozilla_compat.js"); // script com funções
importPackage(java.awt);
importClass(java.awt.Frame);
var frame = new java.awt.Frame("hello");
frame.setVisible(true);
print(frame.title);
– Vários outros recursos (veja referência [8] no final para mais detalhes)
Referências
• Java 8
• [1] http://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
• [2] Apresentações do JavaONE 2013 em http://parleys.com/?reqp=1&reqr=pJ1vLKVhpTW6
• Lambda
• [3] https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
• Date/Time API
• [4] https://docs.oracle.com/javase/tutorial/datetime/
• Streams
• [5] https://docs.oracle.com/javase/tutorial/collections/streams/index.html
• CompletableFuture & paralelismo
• [6] http://www.nurkiewicz.com/2013/05/java-8-definitive-guide-to.html
• [7] https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/changes8.html
• Nashorn
• [8] https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide
• [9] https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn
Atualização Java 8
Helder	da	Rocha
21	de	agosto	de	2014
Exemplos	de	código	serão	disponibilizados	em	github.com/argonavis_br
www.argonavis.com.br www.summa.com.br

Atualização Java 8 (2014)

  • 1.
  • 2.
    Objetivo • Esta apresentaçãoexplora as principais novidades do Java 8 (que foi lançado em março) • O foco será nas mudanças na sintaxe (lambdas), APIs (streams, data e hora) e ferramentas (nashorn) • Não serão discutidas nesta apresentação mudanças na JVM, JavaFX, runtime (Compact profiles) segurança (JCA) nem monitoração (JMC)
  • 3.
    Conteúdo • Parte I- Mudanças na sintaxe da linguagem • 1. Expressões lambda e referências para métodos • 2. Nova sintaxe para interfaces • Parte II - Novas APIs • 3. Data e hora (java.time) • 4. Interfaces funcionais (java.util.function) • 5. API funcional (java.util.stream) • 5. Paralelismo (ForkJoinPool.common()) • 6. API reativa (java.util.concurrent.CompletableFuture) • Parte III - Ferramentas • 7. JavaScript engine API e ferramenta jjs (Nashorn)
  • 4.
    1. Expressões lambda •Uma expressão lambda é uma função anônima • É abstração de uma operação, tratada como se fosse dados, permitindo que seja atribuída a variáveis e retornada/ passada de/para métodos • Tem origem no cálculo lambda (Alonzo Church, 1936) e é usado em programação desde Lisp (1958) • Faz parte de várias linguagens populares: JavaScript, Scala, C#, Go, Swift, Smalltalk, Python
  • 5.
    Programação funcional • Lambdassão uma abstração fundamental em linguagens funcionais • Em orientação a objetos, o estado de objetos é modificado por operações representadas por seus métodos • Na programação funcional, operações são representadas por funções entre objetos imutáveis • Embora não tenha sido concebida como linguagem funcional, é possível programar em Java usando o paradigma funcional • AAPI de streams facilita a programação funcional em Java 8
  • 6.
    Métodos anônimos emJava • Desde Java 1.2 pode-se implementar interfaces anônimas Runnable tarefa = new Runnable() { @Override public void run() { System.out.println("Hello!"); } } • Java 8 vai mais longe com métodos anônimos (lambdas) Runnable tarefa = () -> { System.out.println("Hello!"); } • As chaves são opcionais neste caso: Runnable tarefa = () -> System.out.println("Hello!");
  • 7.
    Sintaxe de expressõeslambda • Novo operador -> (seta) separa parâmetros e expressão • Variáveis usadas no bloco da expressão lambda devem ser efetivamente finais (imutáveis) • Parenteses: obrigatórios se há mais de um parâmetro ou nenhum: • p -> p/2; // mesmo que (p) -> p/2 • () -> 3; // parênteses necessários • (a,b) -> a+b; // parênteses necessários • Declarar tipo dos parâmetros é opcional (se for possível inferir) • int r = p -> p/2; // Implícito: (int p) -> p/2; • Chaves e a instrução return: opcionais se apenas uma instrução • int r = (a,b) -> a+b; // (int a, int b) -> { return a+b;}
  • 8.
    Referências de métodos •O operador :: declara referências para métodos e construtores • Há quatro tipos • Classe::metodoEstatico // referência para metodo estatico • Classe::metodoDeInstancia // ref. para método de um objeto qualquer • objeto::metodoDeInstancia // ref. para método de um objeto específico • Classe::new // referência para construtor • Exemplos System.out::println Comparator::compare HashSet<Integer>::new • Uma referência pode substituir uma expressão lambda; os argumentos são obtidos por inferência (as duas formas abaixo são equivalentes) • Consumer<String> f1 = s -> System.out.println(s); • Consumer<String> f2 = System.out::println; interface Consumer<T> { void accept(T t); } Usará parâmetro T do método por inferência
  • 9.
    2. Sintaxe parainterfaces • Interfaces, a partir de Java 8, podem conter métodos com implementações, desde que sejam • Estáticos (com modificador static) • Default (com novo modificador default) interface Template { default String transform(String s) { return tag(s); } static String tag(String s) { return "<tag>"+s+"</tag>"; } } Upper u = new Upper(); Plain p = new Plain(); System.out.println(Template.tag("A")); System.out.println(u.transform("B")); System.out.println(p.transform("C")); class Plain implements Template { @Override public String transform(String s) { return s; } } class Upper implements Template {} <tag>A</tag> <tag>B</tag> C
  • 10.
    Métodos default • Métodosdefault não precisam ser sobrepostos • Conflito pode haver se uma classe implementa duas interfaces com métodos default iguais • Neste caso é necessário sobrepor o método escolhendo qual implementação usar interface A { default void m() { System.out.println("A"); } } interface B { default void m() { System.out.println("B"); } } class C implements A, B { public void m() { B.super.m(); // escolhendo implementação B } }
  • 11.
    3. Nova APIde datas • Cinco pacotes (java.time + 4 subpacotes) com novas abstrações para intervalos, períodos, datas, meses, eras, anos, unidades, fusos horários, formatação, etc. • Principais abstrações estão no pacote raiz java.time • LocalDate, LocalTime, LocalDateTime • ZoneId, ZonedDateTime • OffsetDateTime, OffsetTime, ZoneOffset • Clock, Duration, Instant, Period • Month, Year, YearMonth, MonthDay, DayOfWeek • Objetos são criados com factory methods
  • 12.
    Data e Hora •LocalDate, LocalTime e LocalDateTime representam data ISO 8601 (calendário Gregoriano) LocalDate date1 = LocalDate.now(); System.out.println(date1); int day = date1.getDayOfMonth(); System.out.println(day); LocalDate date2 = LocalDate.parse("2014-08-20"); System.out.println(date2); LocalDateTime dt = date2.atTime(13, 59); System.out.println(dt); LocalTime time = dt.toLocalTime(); System.out.println(time); LocalTime tonight = time.plusHours(8); System.out.println(tonight); LocalDate someDay = LocalDate.of(1995,5,1); System.out.println(someDay); 2014-08-16 16 2014-08-20 2014-08-20T13:59 13:59 21:59 1995-05-01
  • 13.
    Formatação e parsing •Métodos toString() default utilizam formatações padrão sem a necessidade de usar formatadores • É possível personalizar os formatos para formatação e parsing usando DateTimeFormatter.ofPattern() DateTimeFormatter formato1 = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"); DateTimeFormatter formato2 = DateTimeFormatter.ofPattern("MMMM d, yyyy hh:mm a"); LocalDateTime ldt = LocalDateTime.parse("20/08/2014 13:59", formato1); System.out.println(ldt); String formatted = ldt.format(formato2); System.out.println(formatted); 2014-08-20T13:59 August 20, 2014 01:59 PM
  • 14.
    Duração e período •Instant representa um instante qualquer Instant agora = Instant.now(); // 2014-08-16T14:44:07.989809Z Instant depois = agora.plusSeconds(30); // 2014-08-16T14:44:37.989809Z • Duration representa uma duração de tempo (30 segundos) Duration duracao = Duration.between(agora, depois); // PT30S • Period representa um intervalo entre duas datas (4 meses, 16 dias) Period periodo = 
 Period.between(LocalDate.now(), LocalDate.of(2015, 1, 1)); // P4M16D • Clock permite relógios alternativos (com offset, com resolução de minutos, etc) Clock relogioSistema = Clock.systemUTC(); // Default SystemClock[Z] Clock tictac = 
 Clock.tickMinutes(ZoneId.systemDefault()); // Conta apenas minutos Instant start = tictac.instant(); // 2014-08-16T17:54:00Z Duration elapsed = Duration.between(start, start.plusSeconds(126)); // PT2M6S
  • 15.
    Interface comum • Prefixoscomuns a métodos estáticos em classes do pacote • of - método de fábrica: ZoneId zone = ZoneId.of("GMT"); • parse - método de fábrica: LocalDate d = LocalDate.parse("2014-08-19"); • Prefixos comuns a métodos de instância • get - retorna o valor de algo: int dia = dateTime.getDayOfMonth(); • is - retorna true ou false: boolean bissexto = year.isLeap(); • with - retorna uma cópia modificada: Clock fuso2 = fuso1.withZone(zone); • plus - adiciona uma quantidade: Period p2 = p1.plusDays(5); • minus - subtrai uma quantidade: Instant s2 = s2.minusSeconds(30); • to - converte objeto em outro tipo: int segundos = localTime.toSecondOfDay(); • at - combina objeto com outro: LocalDate data = monthDay.atYear(2014);
  • 16.
    4. Interfaces funcionais •Interface funcional: interface com um método abstrato • Se houver outros métodos devem ser static ou default • Podem ser implementadas usando expressões lambda! • Java 8 introduziu a anotação @FunctionalInterface para identificar interfaces funcionais em tempo de compilação • Haverá erro de compilação se interface não for funcional • O uso de interfaces funcionais em lambdas permite alto grau de reuso: lambdas ignoram tipos recebidos/retornados • O pacote java.util.function contém uma coleção de interfaces padrão para reuso
  • 17.
    java.util.function • 43 interfacesgenéricas de propósito geral • Principais interfaces • Predicate<T>: Recebe (T); Retorna boolean • BiPredicate<T,U>: Recebe (T,U); Retorna boolean • Consumer<T>: Recebe (T); Retorna void • Supplier<T>: Recebe (); Retorna T • Function<T,R>: Recebe (T); Retorna R • BiFunction<T,U,R>: Recebe (T,U); Retorna R • UnaryOperator<T>: Recebe (T); Retorna T • BinaryOperator<T, T>: Recebe (T, T); Retorna T
  • 18.
    Uso de interfacesfuncionais • O nome do método da interface funcional é irrelevante para criar expressões lambda, já que é anônimo; tipos também são irrelevantes • O mais importante são: quantidade de argumentos recebidos e se retorna ou não algum valor • Uma expressão usando Supplier<T> com T = String • Uma expressão usando Function<Integer,String> • Uma expressão usando BiFunction<T, U, R> String produto = () -> "Hello!"; String resultado = (a,b) -> a + b; // concatena ou soma Integer tamanho = s -> s.length(); // recebe String, retorna Integer
  • 19.
    Métodos que recebemlambdas • Um método que recebe uma expressão lambda declara receber uma interface funcional • Pode-se implementar uma função anônima e passá-la como argumento, da mesma forma como são passados os dados public Integer calcular(Function<Integer> funcao, Integer operando) { return funcao.apply(operando); } System.out.println( calcular( n -> n * n, 4); System.out.println( calcular( n -> n / 2, 16);
  • 20.
    5. Streams • Aclasse java.util.stream.Stream fornece uma API para programação funcional baseado na concatenação de operações lazy processadas quando uma operação terminal é chamada • Um Stream conduz elementos de uma fonte através de uma pipeline de operações, produzindo um resultado sem modificar a fonte • Elementos são processados uma única vez (o stream é consumido) • Streams podem ser infinitos (operações intermediárias podem limitar os dados durante o processamento) • Streams podem ser criados/obtidos de várias formas
  • 21.
    Como criar umStream • Um stream pode ser criado a partir de métodos de fábrica: generate(), iterate(), of(), etc. Stream<String> letras = Stream.of("X", "T", "S", "P"); Stream<Integer> infinito = 
 Stream.generate(()-> new Random().nextInt(100)); • É mais comum criar um stream a partir de uma coleção usando o método stream() ou parallelStream() List<Integer> colecao = new ArrayList(); // ... Stream<Integer> colecao.stream(); Stream<Integer> colecao.parallelStream(); // paralelismo • Um stream pode ser transformado via operações intermediárias (lazy) e uma operação terminal (eager - que encerra o stream)
  • 22.
    Operações de umstream • As operações intermediárias (lazy) são executadas apenas depois que o stream é terminado (puxando os dados: método "pull") • Após uma operação terminal o stream não pode ser reusado • As operações recebem interfaces funcionais • Algumas operações. Operações intermediárias retornam Stream: • filter(Predicate<T>): intermediária • map(Function<T,U>): intermediária • flatMap(Function<T,Stream<R>>): intermediária • reduce(BinaryOperator<T>): terminal • forEach(Consumer<T>): terminal • collect(Collector<T,A,R>): terminal Outras operações terminais: min(), max(), count(), etc. Outras intermediárias: skip(), peek(), distinct(), etc.
  • 23.
    Filter • A operaçãointermediária filter(Predicate<T>) remove do stream elementos que não combinam com a função List<Integer> numbers = Arrays.asList(new Integer[] {4,1,9,6,8,3,5}); numbers.stream() .filter(n -> n > 5) .forEach(System.out::println); Imprime 9 6 8
  • 24.
    Map • A operaçãointermediária map(Function<T,U>) recebe uma função que realiza uma transformação no stream (e pode converter um tipo em outro): List<Integer> numbers = Arrays.asList(new Integer[] {4,1,9,6,8,3,5}); numbers.stream() .filter(n -> n > 5) .map(n -> n * n) .forEach(System.out::println); Imprime 81 36 64
  • 25.
    ForEach • O métodoforEach(Consumer<T>) foi adicionado em Iterable e está disponível para qualquer implementação (ex: Collection): list.forEach(System.out::println); • Stream também implementa Iterable e pode chamar forEach(): Stream<Integer> numeros = Stream.of(1,2,3,4); numeros.map(s->s*2).forEach(System.out::println); • ForEach é uma operação terminal (depois de chamada, puxa a execução do stream não permitindo novos métodos): numeros.filter(n->n<3); // exceção (stream encerrado)
  • 26.
    Reduce • reduce(BinaryOperator<T>) éuma operação terminal que retorna resultado da operação de combinação sobre valores acumulados • Há três diferentes versões de reduce (com 1, 2 ou 3 args) • O resultado pode ser do mesmo tipo (T), outro tipo ou Optional<T> (objeto que encapsula T ou null) List<Integer> numbers = Arrays.asList(new Integer[] {4,1,9,6,8,3,5}); Optional<Integer> resultado = numbers.stream() .filter(n -> n > 5) .map(n -> n * n) .reduce((acum, oper) -> a+b); int soma = resultado.get(); // 181 (81+36+64)
  • 27.
    Collect • collect(Collector<T,A,R>) éuma operação terminal que executa uma redução mutável nos elementos do stream. O coletor constrói o resultado usando funções de acumulação e combinação. • collect() pode ser usado para reduzir um stream a uma coleção • Classe utilitária Collectors contém vários algoritmos implementados (toList(), groupingBy(), etc.) Map<String, List<Movie>> directors = movieList.stream() .collect(Collectors.groupingBy(Movie::getDirector)); List<String> titles = movieList.stream() .map(movie -> movie.getTitle() + " (" +movie.getDirector()+ ")") .collect(Collectors.toList());
  • 28.
    FlatMap • flatMap(Function<T,Stream<R>>) éuma operação intermediária que "achata" um stream de streams List<String> titlesAndDirectors = movieList.stream() .flatMap(movie -> Stream.of(movie.getTitle(), movie.getDirector())) .collect(Collectors.toList());
  • 29.
    Exceções e valoresnulos • Streams não podem deixar escapar exceções checadas • É preciso capturar a exceção • Pode-se lançar uma exceção de runtime • Ideal é devolver um objeto comum que contenha informações que permitam lidar com o problema • Objetos Optional podem ser usados para lidar com valores nulos public Optional<Integer> transformar(Integer valor) { try { // operações sobre valor return Optional.of(resultado); } catch (Excecao e) { return Optional.empty(); } } int valor = 123; Optional<Integer> op = transformar(valor); Integer resultado = op.orElse(valor); Retorna resultado ou 123 (se ocorrer exceção e Optional estiver vazio)
  • 30.
    Streams de primitivos •java.util.stream também contém um conjunto de Streams de primitivos como DoubleStream, IntStream e LongStream • Streams comuns podem ser convertidos em streams de primitivos: mapToInt(), mapToDouble(), etc. • IntStream stream = lista.stream().mapToInt(n->n); • Possuem métodos especiais para manipular de primitivos e obter estatísticas IntSummaryStatistics example = Stream.of(9,4,8,2,15,82,91,77,53,27,13) .mapToInt(n->n).summaryStatistics(); System.out.printf("Count: %d, Max: %d, Min: %d, Avg: %f, Sum: %d", example.getCount(), example.getMax(), example.getMin(), example.getAverage(), example.getSum());
  • 31.
    6. Paralelismo • OJava 8 introduziu um ForkJoinPool comum para uso em operações paralelas • Forma recomendada de uso (new ForkJoinPool() passa a ser um anti-pattern) • Configurável via propriedades do sistema • Pool default para streams paralelos e operações assíncronas com CompletableFuture • Para obter uma referência ao pool • ForkJoinTasks podem ser chamadas sem informar um pool ForkJoinPool poolComum = ForkJoinPool.common(); task.invoke(); // em vez de pool.invoke(task) usa poolComum
  • 32.
    7. CompletableFuture • UmaAPI para programação reativa similar à API de streams (mas baseada em "push" - o oposto da API de streams, que é baseada em "pull") • Objetos Future que podem ser concatenados em série • Contém 36 métodos que executam tarefas assíncronas e retornam CompletableFuture: recebem interfaces funcionais • Cada CompletionStage executa um estágio da tarefa CompletionStage CompletionStage CompletionStage CompletableFuture CompletionStageFuture
  • 33.
    Como criar umCompletableFuture • Usando o construtor default CompletableFuture<Integer> future = 
 new CompletableFuture<>(); future.complete(5); • Usando métodos de fábrica com Runnable ou Supplier<V> CompletableFuture<Void> cf1 = 
 CompletableFuture.runAsync(() -> {
 System.out.print("Etapa assíncrona");
 }); CompletableFuture<String> cf2 = 
 CompletableFuture.supplyAsync(() -> {
 return "Etapa assíncrona";
 });
  • 34.
    Concatenação de estágios •Estágios seguintes podem processar dados do estágio anterior (com tarefas Consumer<T>, Function<T,R> e Runnable) • Tarefas podem rodar em threads novos (disparados pelo ForkJoinPool comum) ou escolher um executor próprio • Há métodos para combinar múltiplos estágios anteriores CompletableFuture.supplyAsync(() -> event.get() ) .thenApply( x -> x * x ) .thenAccept ( x -> System.out.println(x) ) .thenRun( () -> System.out.println("Done!") );
  • 35.
    8. Nashorn • JavaScriptengine (javax.script.ScriptEngine) que permite embutir JavaScript dentro de aplicações Java e vice-versa • Código Java pode executar JavaScript e vice-versa e compartilhar dados e operações • Mapeamento automático entre linguagens: tipos são convertidos automaticamente, getters/setters acessíveis como propriedades JSON, coleções Java são tratadas como arrays JavaScript • Também inclui uma ferramenta de linha de comando jjs • Interpretador para programação interativa (REPL) • Permite escrever código JavaScript usando classes e objetos Java
  • 36.
    Chamando JavaScript final ScriptEngineManagerfactory = new ScriptEngineManager(); final ScriptEngine engine = factory.getEngineByName("nashorn"); try { engine.eval("print('JavaScript hello!');"); } catch (ScriptException e) { e.printStackTrace(); } • É necessário obter uma instância de javax.script.ScriptEngine • Método eval() executa código JavaScript contido em String JavaScript hello! OUTPUT
  • 37.
    Chamando função externa finalScriptEngineManager factory = new ScriptEngineManager(); final ScriptEngine engine = factory.getEngineByName("nashorn"); try { engine.eval(new FileReader("target/classes/test.js")); Invocable inv = (Invocable)engine; inv.invokeFunction("printText", "Something"); } catch (ScriptException | FileNotFoundException | NoSuchMethodException e){ ... } • eval() pode carregar um script externo • Invokable.invokeFunction() chama função JavaScript existente no script carregado function printText(text) { print("JavaScript prints: " + text); } test.js JavaScript prints: Something OUTPUT
  • 38.
    Acessando objeto (JSON) finalScriptEngineManager factory = new ScriptEngineManager(); final ScriptEngine engine = factory.getEngineByName("nashorn"); try { ScriptObjectMirror mirror = (ScriptObjectMirror) engine.eval(new FileReader("target/classes/movie.js")); System.out.println(mirror.getMember("title")); System.out.println(mirror.getMember("director")); System.out.println(mirror.getMember("year")); } catch (ScriptException | FileNotFoundException | NoSuchMethodException e) { e.printStackTrace(); } var movie = { "title" : "The Shining", "director" : "Kubrick", "year" : 1980 } movie; movie.js The Shining Kubrick 1980 OUTPUT
  • 39.
    Chamando Java deJavaScript • Função Java.type("pacote.Class") carrega tipos Java e permite usá-los em JavaScript var ArrayList = Java.type("java.util.ArrayList"); var defaultSizeArrayList = new ArrayList; var customSizeArrayList = new ArrayList(16); – Pacotes e classes podem ser importados com importPackage() e importClass() (exemplos do tutorial da Oracle [8]): load("nashorn:mozilla_compat.js"); // script com funções importPackage(java.awt); importClass(java.awt.Frame); var frame = new java.awt.Frame("hello"); frame.setVisible(true); print(frame.title); – Vários outros recursos (veja referência [8] no final para mais detalhes)
  • 40.
    Referências • Java 8 •[1] http://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html • [2] Apresentações do JavaONE 2013 em http://parleys.com/?reqp=1&reqr=pJ1vLKVhpTW6 • Lambda • [3] https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html • Date/Time API • [4] https://docs.oracle.com/javase/tutorial/datetime/ • Streams • [5] https://docs.oracle.com/javase/tutorial/collections/streams/index.html • CompletableFuture & paralelismo • [6] http://www.nurkiewicz.com/2013/05/java-8-definitive-guide-to.html • [7] https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/changes8.html • Nashorn • [8] https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide • [9] https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn
  • 41.