40
Java 8 Nuevas características por Fernando Petrola

Java 8 - Nuevas características

Embed Size (px)

Citation preview

Java 8Nuevas características

por Fernando Petrola

Tópicos:

1.Interfaces funcionales

2.Expresiones Lambda

3.Stream API

4.Nuevo motor de Javascript Nashorn

Interfaces funcionales

Functional Interface:

1. Es una Interface que tiene un solo método abstracto.

2. El annotation @FunctionalInterface se puede usar

como mecanismo de advertencia en la compilación.

3. Se suelen implementar métodos por defecto dentro.

4. Antes de crear una nueva mirar las predefinidas en

java.util.function.*

5. Los tipos de datos primitivos tienen interfaces

funcionales predefinidas específicas.

6. Son usadas en conjunto con expresiones lambdas

public interface ActionListener extends EventListener{

public void actionPerformed(ActionEvent e); }

public interface Callable<V> { public V call(); }

public interface Runnable

{ public void run(); }

public interface Comparator<T>

{

int compare(T o1, T o2);

boolean equals(Object obj);

}

Ejemplos de Functional Interfaces ya conocidas

• Supplier<T>: Devuelve un T• Consumer<T>: Recibe un T• BiConsumer<T, U>: Recibe un T y un U• Predicate<T>: Evalua un T y devuelve un boolean• Function<T, R>: Recive un T y devuelve un R• BinaryOperator<T>: Recibe 2 T y devuelve un T

Functional Interfaces

Predefinidas genéricas

• (Int | Long | Double)Supplier• (Int | Long | Double)Consumer• (Int | Long | Double)Predicate• (Int | Long | Double)Function<R>• (Int | Long | Double)BinaryOperator• Obj(Int | Long | Double)Consumer<T>• (Int | Long | Double)To(Int | Long | Double)Function

Predefinidas para primitivos

Functional Interfaces

Default Methods

1.Permiten definir Interfaces que tengan algo de

comportamiento.

2.Son heredados por las clases implementadoras

3.Al heredar más de una implementación del mismo método

se puede elegir cual usar en la subclase.

4.Facilitan “backward compatibility” de Collections

5.Solo interactúan con otros métodos y son “stateless”.

Ejemplo de default methods

public interface Predicate<T> {

boolean test(T t);

default Predicate<T> and(Predicate<? super T> other) { return (t) -> test(t) && other.test(t);}

default Predicate<T> negate() { return (t) -> !test(t);}

...}

Default Methods

Herencia

public interface A{

default public String foo(){ return “A”;}

}

public interface B{

default public String foo(){ return “B”;}

}

public class AB implements A, B{

public String foo(){ return B.super.foo();}

}

Preguntas sobre interfaces funcionales?

Seguimos con:

Expresiones Lambda

Expresiones Lambda

• Es un bloque de código

• Método anónimo

• Parecido al resultado obtenido con clases

anónimas

• Termina creando una instancia de una interfaz

funcional

Que es una expresión lambda?

Expresiones Lambda

• Código más compacto y limpio

• Da lugar al surgimiento de Streams API

• + declarativo, - implementativo

• Permite aplicar varias optimizaciones

• Inferencia de tipos

• Mismas reglas de scope que los bloques de código

tradicionales

• Primer paso para la inclusión de programación funcional

Ventajas

Expresiones Lambda

• No son funciones reales, son métodos anónimos.

• Sólo permite capturar variables inmutables y miembros

de la clase.

• No se puede declarar la firma de una “funcion” anónima:public static void runOperation((int -> int) operation) { ... }

Contras

Forma básica:

arg -> body

Forma extendida:

( T1 arg1, T2 arg2 ) -> { body }

Como es una expresión lambda?

new InterfaceA(){

public T2 method1(T1 v1) {

return result;}

};

v1 -> result

Misma definición, diferentes expresiones

button.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e) {

System.out.println(“click”);}

});

El ejemplo más esperado.. JButton!

Con clases anónimas

button.addActionListener(e -> System.out.println(“click”));

Con lambdas

;

BinaryOperator<Integer> sumador= new BinaryOperator<Integer>(){

public Integer apply(Integer v1, Integer v2) {

return v1 + v2;}

};

Inferencia de tipos, bloque de código, return

(Integer v1, Integer v2) -> { return v1 + v2; }

ó

(v1, v2) -> { return v1 + v2; }

ó

(v1, v2) -> v1 + v2

BinaryOperator<Integer> sumador=

Interfaces funcionales

// AsignacionPredicate<String> p = String::isEmpty;

// Predicate creado en contexto de la invocacionstream.filter(e -> e.getSize() > 10)...

// En casteostream.map((ToIntFunction) e -> e.getSize())...

// Comparator creado con lambdaString[] list= new String[] { "One", "Two", "Three", "Four", "Five", "Six" };Arrays.sort(list, (a, b)->a.substring(1).compareTo(b.substring(1)));

Creadas a partir de lambdas

• Declaración de variables• Asignaciones• Instrucción “return”• Inicializadores de Arrays• Parámetros de métodos o constructores• Cuerpo de un lambda • Condicionales (?:)• Casteos

Donde se pueden usar lambdas?

FileFilter[] filters= new FileFilter[] { f -> f.exists(), f -> f.getName().startsWith("q") };

Object o = (Runnable) () -> { System.out.println("hola"); };

Supplier<Runnable> c = () -> () -> { System.out.println("hola"); };

Callable<Integer> c = flag ? (() -> 23) : (() -> 42);

Ejemplos para destacar:

En contextos que tengan “target type”:

public class Hola {

Runnable r1 = () -> { System.out.println(this); } Runnable r2 = () -> { System.out.println(toString()); }

public String toString() { return "Hola mundo!"; }

public static void main(String... args) { new Hola().r1.run(); new Hola().r2.run(); } }

Como se maneja el scope?

• Método estático (ClassName::methName)• Método de un instancia (instanceRef::methName)• Método super de un objeto particular (super::methName)• Método de instancia de un tipo (ClassName::methName)• Constructor de clase (ClassName::new)• Constructor de arreglo (TypeName[]::new)

Otra forma de lambda: referencia a método

Collection<String> knownNames= Arrays.asList("Hello", "Java", "World", "8", "Streams");

Predicate<String> isKnown = knownNames::contains;

Function<String, String> upperfier = String::toUpperCase;

IntFunction<int[]> arrayMaker = int[]::new;

int[] array = arrayMaker.apply(10); // crea un arreglo int[10]

Ejemplos:

Tipos de referencias a metodos

interface Getter<O, T>{

T get(O obj);}

Funcionalidad emergente: Reflection Refactorizable!!

interface Setter<O, T>{

void set(O obj, T param);}

public class ClaseA{

int field1;public int getField1(){

return field1;}public void setField1(int field1){

this.field1= field1;}public static void main(String[] args){Getter<ClaseA, Integer> getter= ClaseA::getField1;

Setter<ClaseA, Integer> setter= ClaseA::setField1;

ClaseA obj= new ClaseA();setter.set(obj, 10);Integer value= getter.get(obj);

}}

Funcionalidad emergente: Reflection Refactorizable!!

public class RefactoringEnabledHibernateMapper<T>{

public RefactoringEnabledHibernateMapper(Supplier<T> supplier) {...}public <V> void setIdAccessors(Getter<T, V> getter, Setter<T, V> setter) {...}public <V> void addPropertyAccessors(Getter<T, V> getter, Setter<T, V> setter) {...}

}

RefactoringEnabledHibernateMapper<Person> mapper= new RefactoringEnabledHibernateMapper<Person>(Person::new);mapper.setIdAccessors(Person::getId, Person::setId);mapper.addPropertyAccessors(Person::getName, Person::setName);mapper.addPropertyAccessors(Person::getAge, Person::setAge);

RefactoringEnabledHibernateMapper

Preguntas sobre expresiones lambda?

Seguimos con:

Stream API

Streams API

• Un stream es una secuencia de elementos generada a

partir de:

• Collections

• Arrays

• Generators (on the fly)

• I/O Channels

• Los streams no guardan los elementos

• Mecanismo de procesamiento con pipeline de operaciones.

• En el procesamiento se aplican varias técnicas de

optimización.

• Las expresiones lambda le aportan mucha legibilidad.

• Provee mecanismo versátil para recolectar los resultados.

Streams API

Pipeline de operaciones

sourceoperation

1operation

N terminal operation....

collectionarray

I/O channelgenerated

map, filter, distinct, sorted, peek, limit, parallel, sequencial, unordered, reduce, sum, skip

forEach, toArray, reduce, collect,

min, max, count, anyMatch, allMatch,

noneMatch, findFirst, findAny,

iterator

Streams APIProcesamiento de un stream

.map(Integer::parseInt)

.limit(3)

.forEach(i -> System.out.println(i))

.filter(i -> i % 2 != 0)

“1”

“2”

“3”

“1”

“2”

“3”

1 2 3

1 3

“4”

“5”

Stream.of("1", "2", "3", "4", "5")

Streams APIEjemplos

List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, -4);

List<Integer> distinct = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());

IntStream.range(0, 100).parallel().filter(i -> i % 2 == 0).forEach(System.out::println);

List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada"); String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));

List names = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");

Predicate<String> startsWithJ = n -> n.startsWith("J");

Predicate<String> fourLetterLong = n -> n.length() == 4;

names.stream()

.filter(startsWithJ.and(fourLetterLong))

.forEach((n) -> System.out.print("Empieza con J y tiene 4 caracteres: " + n));

Streams APIEjemplos

Map<City, Set<String>> namesByCity= people.stream().collect(Collectors.groupingBy (

Person::getCity, Collectors.mapping (Person::getLastName, toSet())));

Resultado: Obtiene los apellidos de las personas en cada ciudad

IntStream.iterate(0, i -> i + 2).limit(5).forEach(System.out::println);

Resultado: imprime 0, 2, 4, 6, 8

Streams API

Name Returns Interface Lambda

signature

filter Stream<T> lazy Predicate<T> T -> boolean

map Stream<U> lazy Function<T, U> T -> U

sorted Stream<T> lazy Comparator<T> (T, T) -> int

limit Stream<T> lazy n/a n/a

skip Stream<T> lazy n/a n/a

reduce T eager BinaryOperator<T

>

(T, T) -> T

findFirst T eager n/a n/a

groupBy Map<U,

Collection<T>>

eager Function<T, U> T -> U

forEach void eager Consumer<T> T -> void

Resumen de operaciones

Preguntas sobre Stream API?

Seguimos con el:

Motor de Javascript Nashorn

Motor de Javascript Nashorn

1. Correr código dinámico Javascript nativo en la JVM

2. Se basa en el uso del nuevo bytecode InvokeDynamic,

presentado en Java 7

3. Soporta la especificación ECMAScript 5.1

4. De 2 a 10x la velocidad de Rhino

5. Se acerca mucho más a la performance de V8, según

algunos benchmarks llega a la mitad de velocidad.

a. Tener en cuenta que V8 es exclusivo para JS.

b. Nashorn recien esta naciendo.

Motor de Javascript NashornInvocación desde línea de comando

$ cd /usr/bin$ ln -s $JAVA_HOME/bin/jjs jjs$ jjsjjs> print('Hello World');

Archivo: hello.js

var hello = function() { print("Hello Nashorn!");};

hello();

$ jjs hello.jsHello Nashorn!

Motor de Javascript NashornEjemplo de invocación

script.js:var fun1 = function(name) { print('Hi there from Javascript, ' + name); return "greetings from javascript";};

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");engine.eval(new FileReader("script.js"));

Invocable invocable = (Invocable) engine;Object result = invocable.invokeFunction("fun1", "Peter Parker");System.out.println(result);

Motor de Javascript NashornStreams

var list2 = new java.util.ArrayList();

list2.add("ddd2");

list2.add("aaa2");

list2.add("aaa3");

list2

.stream()

.filter(function(el) {

return el.startsWith("aaa");

})

.sorted()

.forEach(function(el) {

print(el);

});

Motor de Javascript NashornComo extender clases de Java

var Runnable = Java.type('java.lang.Runnable');

var Printer = Java.extend(Runnable, {

run: function() {

print('printed from a separate thread');

}

});

var Thread = Java.type('java.lang.Thread');

new Thread(new Printer()).start();

new Thread(function() {

print('printed from another thread');

}).start();

Fin