Skip to content

Latest commit

 

History

History
357 lines (255 loc) · 8.44 KB

README_ES.md

File metadata and controls

357 lines (255 loc) · 8.44 KB

JAVA 8 - Chuleta

Expresión Lambda

(int a) -> a * 2; // Calcula el docble de a
a -> a * 2; // o simplemente sin tipo
(a, b) -> a + b; // Suma 2 parametros

Si lambda tiene mas de una expresión podemos usar { } y return

(x, y) -> {
    int sum = x + y;
    int avg = sum / 2;
    return avg;
}

Una expresión lambda no puede usarse sola en Java, necesita estar asociada a un interfaz funcional

interface MyMath {
    int getDoubleOf(int a);
}

MyMath d = a -> a * 2; // asociado a un interfaz
d.getDoubleOf(4); // es 8

Todos los ejemplos con "list" usan:

List<String> list = [Bohr, Darwin, Galilei, Tesla, Einstein, Newton]

Colecciones

sort sort(list, comparator)

list.sort((a, b) -> a.length() - b.length())
list.sort(Comparator.comparing(n -> n.length())); // igual
list.sort(Comparator.comparing(String::length)); // igual
//> [Bohr, Tesla, Darwin, Newton, Galilei, Einstein]

removeIf

list.removeIf(w -> w.length() < 6);
//> [Darwin, Galilei, Einstein, Newton]

merge merge(key, value, remappingFunction)

Map<String, String> names = new HashMap<>();
names.put("Albert", "Ein?");
names.put("Marie", "Curie");
names.put("Max", "Plank");

// El valor "Albert" existe
// {Marie=Curie, Max=Plank, Albert=Einstein}
names.merge("Albert", "stein", (old, val) -> old.substring(0, 3) + val);

// El valor  "Newname" no existe
// {Marie=Curie, Newname=stein, Max=Plank, Albert=Einstein}
names.merge("Newname", "stein", (old, val) -> old.substring(0, 3) + val);

Expresión de metodo Class::staticMethod

Permite referenciar métodos (y constructores) sin ejecutarlos

// Con Lambda:
getPrimes(numbers, a -> StaticMethod.isPrime(a));

// Metodo Referenciado:
getPrimes(numbers, StaticMethod::isPrime);
Método Referenciado Forma de Lambda
StaticMethod::isPrime n -> StaticMethod.isPrime(n)
String::toUpperCase (String w) -> w.toUpperCase()
String::compareTo (String s, String t) -> s.compareTo(t)
System.out::println x -> System.out.println(x)
Double::new n -> new Double(n)
String[]::new (int n) -> new String[n]

Streams

Similares a las colecciones, pero:

  • No almacenan su propia información
  • La información viene de otra parte (colleciones, archivos, db, web, ...)
  • immutable (crean un nuevo stream)
  • lazy (solo computa lo que es necesario !)
// Computara 3 "filter"
Stream<String> longNames = list
   .filter(n -> n.length() > 8)
   .limit(3);

Crea un nuevo stream

Stream<Integer> stream = Stream.of(1, 2, 3, 5, 7, 11);
Stream<String> stream = Stream.of("Jazz", "Blues", "Rock");
Stream<String> stream = Stream.of(myArray); // or from an array
Stream<String> stream = list.stream(); // or from a list

// Stream infinito [0; inf[
Stream<Integer> integers = Stream.iterate(0, n -> n + 1);

Resultado de las colecciones

// Collect into an array (::new is the constructor reference)
// Colecciona en un array (::new es la referencia del contructor)
String[] myArray = stream.toArray(String[]::new);

// Collecciona en un List o Set
List<String> myList = stream.collect(Collectors.toList());
Set<String> mySet = stream.collect(Collectors.toSet());

// Collecciona en un String
String str = list.collect(Collectors.joining(", "));

map map(mapper)
Aplica una función a cada elemento

// Aplica "toLowerCase" a cada elemento
Stream<String> res = stream.map(w -> w.toLowerCase());
Stream<String> res = stream.map(String::toLowerCase);
//> bohr darwin galilei tesla einstein newton

Stream<Integer> res = Stream.of(1, 2, 3, 4, 5).map(x -> x + 1);
//> 2 3 4 5 6

filter filter(predicado)
Retiene elementos que coinciden con el predicado

// Filtra elementos que empiecen con "E"
res = stream.filter(n -> n.substring(0, 1).equals("E"));
//> Einstein

res = Stream.of(1, 2, 3, 4, 5).filter(x -> x < 3);
//> 1 2

reduce
Reduce los elementos a un unico valor

String reduced = stream.reduce("", (acc, el) -> acc + "|" + el);
//> |Bohr|Darwin|Galilei|Tesla|Einstein|Newton

limit limit(maxSize)
Los n primeros elementos

res = stream.limit(3);
//> Bohr Darwin Galilei

skip
Descarta los primeros n elementos

res = strem.skip(2); // skip Bohr and Darwin
//> Galilei Tesla Einstein Newton

distinct
Borra los elementos repetidos

res = Stream.of(1, 0, 0, 1, 0, 1).distinct();
//> 1 0

sorted
Ordena elementos (debe ser Comparable)

res = stream.sorted();
//> Bohr Darwin Einstein Galilei Newton Tesla 

allMatch / noneMatch

// Comprueba si hay una "e" en cada elemento
boolean res = words.allMatch(n -> n.contains("e"));

anyMatch: Comprueba si hay una "e" en algun elemento
noneMatch: Comprueba si no hay una "e" en ningun elemento

parallel
Devuelve un stream equivalente que es paralelo

findAny
Mas rapido que findFirst en un stream paralelo

Streams de tipo primitivo

Los wrappers (como Stream) son ineficientes. Requieren de embalar y desembalar cada elemento demasiado. Mejor usar IntStream, DoubleStream, etc.

Creacion

IntStream stream = IntStream.of(1, 2, 3, 5, 7);
stream = IntStream.of(myArray); // de un array
stream = IntStream.range(5, 80); // rango de 5 a 80

Random gen = new Random();
IntStream rand = gen(1, 9); // stream de aleatorios

Usa mapToX (mapToObj, mapToDouble, etc.) si la función produce un valor Object, double, etc.

Resultados agrupados

Collectors.groupingBy

// Agrupados por longitud
Map<Integer, List<String>> groups = stream.collect(Collectors.groupingBy(w -> w.length()));
//> {4=[Bohr], 5=[Tesla], 6=[Darwin, Newton], 7=[Galilei], 8=[Einstein]}

Collectors.toSet

// Igual que antes pero en un Set
Map<String, Set<String>> groups2 = stream.collect(Collectors.groupingBy(w -> w.substring(0, 1), Collectors.toSet()));
//> {B=[Bohr], T=[Tesla], D=[Darwin], E=[Einstein], G=[Galilei], N=[Newton]}

Collectors.counting
Cuenta el numero de elementos en una coleccion

Collectors.summing__
summingInt, summingLong, summingDouble para sumar valores de un grupo

Collectors.averaging__
averagingInt, averagingLong, ...

// Longitud promedio de cada elemento de un grupo
Collectors.averagingInt(String::length)

PS: No olvides Optional (como Map<T, Optional<T>>) con algunos metodos de Colecciones (like Collectors.maxBy).

Streams Paralelos

Creacion

Stream<String> parStream = list.parallelStream();
Stream<String> parStream = Stream.of(myArray).parallel();

unordered Pueden acelerar el limit o distinct

stream.parallelStream().unordered().distinct();

PS: Trabaja con la librería de streams. Pe: usa filter(x -> x.length() < 9) en vez de forEach con unif.

Optional

En Java, es común usar null para denotar ausencia de resultado.
Problemas cuando no se comprueban: NullPointerException.

// Optional<String> contiene un string o nada
Optional<String> res = stream
   .filter(w -> w.length() > 10)
   .findFirst();

// longitud de res o "", si no trae nada
int length = res.orElse("").length();

// lanza el lambda si no trae nada
res.ifPresent(v -> results.add(v));

Devuelve un Optional

Optional<Double> squareRoot(double x) {
   if (x >= 0) { return Optional.of(Math.sqrt(x)); }
   else { return Optional.empty(); }
}

Note en la inferencia de la limitación

interface Pair<A, B> {
    A first();
    B second();
}

Un stream de tipo Stream<Pair<String, Long>> :

  • stream.sorted(Comparator.comparing(Pair::first)) // vale
  • stream.sorted(Comparator.comparing(Pair::first).thenComparing(Pair::second)) // no funciona

Java no puede inferir el tipo para la parte de .comparing(Pair::first)y devolver el Objeto, por lo que Pair::first no podría ser aplicado.

El tipo requerido para toda la expresión no puede ser propagada a través de la llamada del método (.thenComparing) y ser usada para inferir el tipo de la primera parte.

El tipo debe ser dado explicitamente

stream.sorted(
    Comparator.<Pair<String, Long>, String>comparing(Pair::first)
    .thenComparing(Pair::second)
) // ok

Esta cheat sheet esta basada en la lección de Cay Horstmann http://horstmann.com/heig-vd/spring2015/poo/