Home » Lambda
Archiv der Kategorie: Lambda
Reihen generiern mit Stream-API
public class LerneUnendlicheReihen { public static void main(String[] args) { IntStream reihe = IntStream.iterate(100, i -> ++i); reihe.limit(100).forEach(System.out::println); /** * Output: * 100 * 101 * ...usw... * 199 */ "abcdefg".chars().forEach(System.out::println); System.out.println("Nun mit Integer Objekten:"); AtomicInteger atomicInteger = new AtomicInteger(100); Stream<Integer> objektReihe = Stream.generate(atomicInteger::getAndIncrement); objektReihe.limit(10).forEach(System.out::println); /* Ausgabe: Nun mit Integer Objekten: 100 101 * ...usw... 109 */ } }
Stream Reduce anwenden, um Auswertungen über Elemente zu machen
import static org.assertj.core.api.Assertions.assertThat; public class LerneReduce { public static void main(String[] args) { List<String> bros = TestDataProvider.getBrothersInArms(); assertThat( bros.stream().reduce((a, b) -> a + ", " + b).get() ).isEqualTo("Walther, Hans, Erich, Paul"); IntStream oneTo3 = IntStream.iterate(1, i -> ++i).limit(3); assertThat( oneTo3.reduce((i1, i2) -> i1 + i2).getAsInt() ).isEqualTo(6); } }
Comparator – Schnelles Erstellen
Comparator personaComparator = Comparator.<strong>comparing</strong>(Persona::getAge).<strong>thenComparing</strong>(Persona::getName))
import static org.assertj.core.api.Assertions.assertThat; public class LerneComparator { final static Persona JONA = new Persona(7, "Jona"); final static Persona ZORA = new Persona(11, "Zora"); final static Persona NATASHA = new Persona(22, "Natasha"); final static Persona[] personas = {JONA, ZORA, NATASHA}; public static void main(String[] args) { List<Persona> personList = Arrays.asList(personas); System.out.println("Mit Comparator:"); Collections.sort(personList, Comparator.comparing(Persona::getAge).thenComparing(Persona::getName)); assertThat(personList).containsExactly(JONA, ZORA, NATASHA); System.out.println("Mit Comparator (reverse order):"); Collections.sort(personList, Comparator.comparing(Persona::getAge).thenComparing(Persona::getName).reversed()); assertThat(personList).containsExactly(NATASHA, ZORA, JONA); System.out.println("Mit Comparable Objects: "); Collections.sort(personList); //Persona must implement Comparable-Interface assertThat(personList).containsExactly(JONA, NATASHA, ZORA); } }
Kumulierbare/verknüpfbare Kriterien erstellen mit Hilfe von Functional interfaces/Lambda (Übung) / Fluent Interface / Method Chaining
Java 8 – Lösung:
public interface Specification<T> { default Specification<T> and(Specification spec){ Specification<T> outerSpec = this; return obj -> outerSpec.isSatisfiedBy(obj) && spec.isSatisfiedBy(obj); } boolean isSatisfiedBy(T obj); }
Erklärung:
Eine Spezifikation definiert (in isSatisfiedBy(T obj)) wann sie erfüllt ist.
Die and(..) Methode gibt eine Kombination aus der vorliegenden (this) und der übergebenen Spezifikation zurück.
Aufruf:
import static org.assertj.core.api.Assertions.assertThat; public class Test { public static void main(String[] args) { Specification<String> istHans = s -> s.equals("Hans"); Specification<String> laengeNichtNull = s -> !s.isEmpty(); Specification<String> kombinierteSpezifikation = istHans.and(laengeNichtNull); assertThat(kombinierteSpezifikation.isSatisfiedBy("Hans")) .as("Kombinierte Spezifikation trifft zu").isTrue(); assertThat(kombinierteSpezifikation.isSatisfiedBy("Peter")) .as("Kombinierte Spezifikation trifft nicht auf 'Peter' zu").isFalse(); assertThat(laengeNichtNull.isSatisfiedBy("Peter")) .as("Nur die eine Spezifikation (nicht leer) trifft zu").isTrue(); /** * Spezifikation kann auch anders parametrisiert werden: */ Specification<Integer> groesser7 = i -> i.compareTo(7) > 0; Specification<Integer> istGerade = i -> (i & 1) == 0; assertThat(groesser7.and(istGerade).isSatisfiedBy(8)).isTrue(); assertThat(groesser7.and(istGerade).isSatisfiedBy(9)).isFalse(); assertThat(groesser7.and(istGerade).isSatisfiedBy(6)).isFalse(); } }
Begriffe:
Fluent API: Wenn Aufrufe aneinander gekettet werden können, dass dabei eine natürlich verständliche Aussage wiedergegeben wird, z.B.:
assertThat(laengeNichtNull.isSatisfiedBy("Peter")) .as("Nur die eine Spezifikation (nicht leer) trifft zu").isTrue();
Method Chaining: Verkettung von Methoden-Aufrufen (wie eben gezeigtes Beispiel). Dabei wird oft ein Object derselben Klasse wir das Objekt auf der die Methode aufgerufen wird zurück gegeben:
public class Klasse { ... //Method that allows chaining Klasse addName(String s){ ... } }
Zum Vergleich eine Version ohne Java 8 Fetures:
public interface Specification<T> { Specification<T> and(Specification spec); boolean isSatisfiedBy(T obj); }
Da Default-Methoden als Sprachmittel fehlen wird die Methode and(..) in einer abstrakten Klasse implementiert:
public abstract class SpecificationImpl<T> implements Specification<T> { public Specification<T> and(Specification spec){ Specification<T> outerSpec = this; return new SpecificationImpl<T>() { @Override public boolean isSatisfiedBy(T obj) { return outerSpec.isSatisfiedBy(obj) && spec.isSatisfiedBy(obj); } }; } }
Aufruf:
Die konkreten Spezifikationen müssen (z.B. als anonyme) Klassen ausprogrammiert werden:
public class Test { public static void main(String[] args) { SpecificationImpl<String> istHans = new SpecificationImpl<String>() { @Override public boolean isSatisfiedBy(String s) { return s.equals("Hans"); } }; SpecificationImpl<String> laengeNichtNull = new SpecificationImpl<String>() { @Override public boolean isSatisfiedBy(String s) { return !s.isEmpty(); } }; Specification<String> kombinierteSpezifikation = istHans.and(laengeNichtNull); assertThat(kombinierteSpezifikation.isSatisfiedBy("Hans")) .as("Kombinierte Spezifikation trifft zu").isTrue(); assertThat(kombinierteSpezifikation.isSatisfiedBy("Peter")) .as("Kombinierte Spezifikation trifft nicht auf 'Peter' zu").isFalse(); assertThat(laengeNichtNull.isSatisfiedBy("Peter")) .as("Nur die eine Spezifikation (nicht leer) trifft zu").isTrue(); /** * Spezifikation kann auch anders parametrisiert werden: */ SpecificationImpl<Integer> groesser7 = new SpecificationImpl<Integer>() { @Override public boolean isSatisfiedBy(Integer i) { return i.compareTo(7) > 0; } }; Specification<Integer> istGerade = new SpecificationImpl<Integer>() { @Override public boolean isSatisfiedBy(Integer i) { return (i & 1) == 0; } }; assertThat(groesser7.and(istGerade).isSatisfiedBy(8)).isTrue(); assertThat(groesser7.and(istGerade).isSatisfiedBy(9)).isFalse(); assertThat(groesser7.and(istGerade).isSatisfiedBy(6)).isFalse(); } }
Zum Vergleich nochmals:
< Java 8: | Java 8: Lambda |
---|---|
SpecificationImpl<String> laengeNichtNull = new SpecificationImpl<String>() { @Override public boolean isSatisfiedBy(String s) { return !s.isEmpty(); } }; |
Specification<String> istHans = s -> s.equals("Hans"); |
Lambda mit mehreren parametern – Comparator
new Comparator<HealthCheckPosition>(){ @Override public int compare(HealthCheckPosition o1, HealthCheckPosition o2) { return DateTimeComparator.getDateOnlyInstance().compare(o1.getInstrument().getRelevantExpirationDate(), o2.getInstrument().getRelevantExpirationDate()); } };
Als Lambda:
(Comparator<HealthCheckPosition>) (o1, o2) -> DateTimeComparator.getDateOnlyInstance().compare(o1.getInstrument().getRelevantExpirationDate(), o2.getInstrument().getRelevantExpirationDate());
Mittels Stream API Flache Liste von Liste von Listen erstellen
Beispiel:
List<List<Object>> list = ...
List<Object> flat =
list.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
(taken from)
Erklärung:
// List of Lists: List<List<String>> listOfLists = new ArrayList<>(); listOfLists.add(Arrays.asList("Buenos Aires", "Córdoba", "La Plata")); listOfLists.add(Arrays.asList("Bern", "Chur", "Luzern")); List<String> result = listOfLists.stream().flatMap(list -> list.stream()).collect(Collectors.toList());
Signatur von flatMap(..):
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
T : Das Element mit dem der Stream parametrisiert ist, auf dem flatMap(..) aufgerufen wird.
Von flatMap verlanges Functional interface:
Function<? super T, ? extends Stream<? extends R>> :
interface Function<T, R> { R apply(T t); }
Das heisst bezüglich übergebener Funktion/Lambda-Expression:
Input von apply: Ist gleich dem Element-Parameter des Streams auf dem flatMap aufgerufen wird.
Output von apply: <? extends Stream<? extends R>>:
Ein Stream von irgendwas. –> Ich darf selbst bestimmen, was R dann wirklich ist. Dadurch, wie meine übergebene Funktion aktuell parametrisiert ist, wird R erst bestimmt.
Mittels Stream API Flache Liste von Map von Listen erstellen:
private List getAllAepfel(Map<UID, List<Apfel>> uidToApfelList) { List xq = uidToApfelList.values().stream().flatMap(List::stream).collect(Collectors.toList()); }