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());
}