Collections bieten einen direkten Zugriff auf die Elemente um Sie zu verwalten.
Eine Sequenz (Abfolge) von Elementen, die funktionale Operationen (Funktionale Interfaces) unterstützt, um Daten zu verarbeiten, transformieren und aggregieren
public class Main {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.stream() // source
.filter(name -> name.length > 4) //inter-
.map(name -> name.toUpperCase()) //mediate
.limit(12) //operations
.forEach(System.out::println); // terminal operation
}
}
public class Main {
public static void main(String[] args) {
// Collection.stream(); // interface
// → Klassen die Collection implementieren:
ArrayList<Student> students = new ArrayList<>();
students.stream();
HashMap<String, Student> map = new HashMap<>();
map.keySet().stream();
map.entrySet().stream();
map.values().stream();
}
}
public class Main {
public static void main(String[] args) {
// Array in ein Stream konvertieren:
// Arrays.stream(T[])
Stream<Integer> num1 = Arrays.stream({ 1, 2, 3, 4 });
int[] numArray = { 1, 2, 3, 4 };
Stream<Integer> num2 = Arrays.stream(numArray);
}
}
public class Main {
public static void main(String[] args) {
// Gleichartige Werte in ein Stream kovertieren:
// Stream.of(T...);
Stream<Integer> num1 = Stream.of(1, 2, 3, 4);
}
}
sind Methoden eines Streams, die als Rückgabewert einen Stream zurückgeben.
Stream KlasseStream<T> filter(Predicate<? super T> predicate)
Der Parameter predicate muss das Predicate Interface implementieren.
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.filter(number -> number > 3);
// nur 4 bleibt übrig
}
}
<R> Stream<R> map(Function<? super T,? extends R> mapper)
Der Parameter mapper muss das Function Interface implementieren.
Die Eingabe vom Typ T definiert der vorherige Stream. Der Rückgabetyp des mapper Parameters definiert den Rückgabetyp des Streams.
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.map(number -> number * 2);
// Rückgabetyp: Stream<Integer>
Stream.of(1, 2, 3, 4)
.map(number -> String.valueOf(number));
// Rückgabetyp: Stream<String>
}
}
Stream<T> limit(long maxSize)
Es werden maximal "maxSize" Elemente des vorherigen Streams weitergegeben.
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.limit(2);
// nur 1 & 2 werden weitergegeben
}
}
Stream<T> skip(long n)
Es werden n-Elemente übersprungen.
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.skip(2);
// nur 3 & 4 werden weitergegeben
}
}
Stream<T> sorted(Comparator<? super T> comparator)
Der Parameter comparator muss das Comparator Interface implementieren.
public class Main {
public static void main(String[] args) {
Stream.of(4, 3, 2, 1)
.sorted((n1, n2) -> Integer.compare(n1, n2));
// 1, 2, 3, 4
// Sagt Bye Bye zu Collections.sort()
}
}
Stream<T> distinct()
Es werden nur einzigartige Werte im Stream beibehalten. Diese werden Mithilfe von .equals identifiziert.
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 1, 4)
.distinct();
// nur 1, 2 & 4 werden weitergegeben
}
}
Intermediate Operations werden auf einem Stream aufgerufen und geben immer einen Stream zurück.
Mit Matching kann abgefragt werden ob bestimmte Elemente einer Bedingung entsprechen.
boolean allMatch(Predicate<T> predicate) // alle
boolean noneMatch(Predicate<T> predicate) // keiner
boolean anyMatch(Predicate<T> predicate) // mindestens einer
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.allMatch(number -> number > 3); // false
Stream.of(1, 2, 3, 4)
.noneMatch(number -> number > 4); // true
Stream.of(1, 2, 3, 4)
.anyMatch(number -> number > 2); // true
}
}
Mit findAny und findFirst wird das erste Element in einem Stream zurückgegeben.
Optional<T> findAny() // nicht deterministisch
Optional<T> findFirst() // deterministisch
Hauptsächlich wichtig bei parallelen Streams
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.filter(number -> number > 1)
.findAny() // 2, 3 oder 4
Stream.of(1, 2, 3, 4)
.filter(number -> number > 1)
.findFirst() // immer 2
}
}
Die Ergebnismenge wird gesammelt.
List<T> toList()
T[] toArray()
T reduce(T identity, BinaryOperator<T> accumulator)
R collect(Collector<T,A,R> collector)
public class Main {
public static void main(String[] args) {
List<Integer> nums = Stream.of(1, 2, 3, 4)
.filter(number -> number > 1)
.toList() // List<Integer>
Object[] nums2 = Stream.of(1, 2, 3, 4)
.filter(number -> number > 1)
.toArray() // Object[]
}
}
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.reduce(0, (a, b) -> a + b); // int *NKR
}
}
public class Main {
public static void main(String[] args) {
ArrayList<Student> students = getManyStudents()
.stream()
.collect(Collectors.toList());
// Collectors.toMap ist Klausurrelevant
// Collectors.groupingBy ist Klausurrelevant
}
}
Mit Statistik Operationen lassen sich Anzahl, Minimum, Maximum, Summe und Durchschnitt berechnen.
long count()
Optional<T> min(Comparator<? super T> comparator)
Optional<T> max(Comparator<? super T> comparator)
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.count(); // 4
}
}
public class Main {
public static void main(String[] args) {
Optional<Integer> min = Stream.of(1, 2, 3, 4)
.min((n1, n2) -> Integer.compare(n1, n2));
min.ifPresent(System.out::println); // 1
}
}
public class Main {
public static void main(String[] args) {
Optional<Integer> max = Stream.of(1, 2, 3, 4)
.max((n1, n2) -> Integer.compare(n1, n2));
max.ifPresent(System.out::println); // 4
}
}
Für die Methoden Durchschnitt und Summe werden spezifische Streams benötigt:
Um einen Statistik Stream zu erzeugen gibt es Intermediate Operations
DoubleStream mapToDouble(ToDoubleFunction<T> mapper)
IntStream mapToInt(ToIntFunction<T> mapper)
LongStream mapToLong(ToLongFunction<T> mapper)
public class Main {
public static void main(String[] args) {
ArrayList<Student> students = getManyStudents();
IntStream studentAges = students.stream()
.mapToInt(student -> student.age());
}
}
long sum()
OptionalDouble average()
public class Main {
public static void main(String[] args) {
IntStream manyNumbers = getManyNumbers();
long sum = manyNumbers.sum();
}
}
public class Main {
public static void main(String[] args) {
IntStream manyNumbers = getManyNumbers();
manyNumbers.average()
.ifPresent(System.out::println);
}
}
Mit forEach kann jedes einzelne Element nacheinander weiterverarbeitet werden.
void forEach(Consumer<T> consumer)
public class Main {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4)
.filter(number -> number > 1)
.forEach(System.out::println)
Stream.of(1, 2, 3, 4)
.filter(number -> number > 1)
.forEach(n -> System.out.println(n));
}
}