Stream

Stream ehk voog on andmete liikumise kanal. Igast kollektsioonist saab moodustada voo, mille peal on võimalik opereerida kasutades Stream API’t. Selle kasutamine suurendab loetavust ja vähendab boilerplate. Sellega kaob vajadus tsüklite järele.

Streamil on kahte tüüpi operatsioone:

  • Intermediate operatsioonid on laisad ja tagastavad uue striimi. Näiteks filter() kasutamine ei hakka kohe midagi filtreerima, vaid loob uue voo. Uut voogu läbides näeb seal ainult predikaadile vastavaid ehk filtreeritud elemente.

  • Terminal operatsioonid on entusiastlikud ja võivad voo läbi käia tekitades mingit kõrvalmõju või saades kätte mingi tulemuse. Sellised on näiteks collect() ja sum(). Peale terminal operatsiooni ei saa striimi enam kasutada.

Näited intermediate operatsioonidest

.filter() tagastab uue striimi, mis sisaldab ainult elemente, mis vastavad predikaadile. seejärel loeb .count() kokku elementide arvu.

long numbersHigherThanFive = Stream.of(7, 2, 3, 5, 6)
                .filter(n -> n > 5)
                .count();
        System.out.println(numbersHigherThanFive); // 2

.map() rakendab etteantud funktsiooni igale elemendile. Vaata ka mapToInt(), mapToLong() ja mapToDouble()

List<Integer> words = Stream.of("a", "ab", "abc")
        .map(s -> s.length()) // with method reference .map(String::length)
        .collect(Collectors.toList());

.peek() hea vahend debug info kogumiseks jaoks.

List<String> names = Stream.of("Bob", "tim", "Alice")
        .filter(s -> Character.isUpperCase(s.charAt(0)))
        .peek(s -> System.out.println(s)) // with method reference .peek(System.out::println)
        .map(s -> s.toUpperCase()) // with method reference .map(String::toUpperCase)
        .collect(Collectors.toList());

.distinct() jätab equals() alusel alles ainult unikaalsed elemendid. .limit() paneb piiri elementide arvule. .sorted() sorteerib elemendid kasvavas järjestuses.

List<Integer> numbers = Stream.of(3, 2, 4, 4, 4, 1)
        .distinct()
        .limit(3)
        .sorted()
        .collect(Collectors.toList());

Näited terminal operatsioonidest

.forEach() opereerib igal elemendil voos sarnaselt tavalise for loopiga.

Stream.of("a", "b").forEach(e -> System.out.println(e)); // .forEach(System.out::println)

.reduce() kombineerib voo elemendid BinaryOperator alusel.

int sum = IntStream.of(7, 3).reduce(0, (a, b) -> a + b);

collect() loob voost mingi kollektsiooni (näiteks listi).

List<String> filtered = Stream.of("ok", "yup")
        .filter(s -> s.startsWith("o"))
        .collect(Collectors.toList());

max() ja min() leiavad vastavalt maksimaalse ja minimaalse väärtuse.

OptionalInt max = IntStream.of(6, 7, 8).max();
OptionalInt min = IntStream.of(6, 7, 8).min();

.anyMatch(), allMatch(), noneMatch() vaatavad voos vähemalt ühe elemendi, kõike elementide või mitte ühtegi elemendi vastavust predikaadile.

List<String> days = Arrays.asList("Saturday", "Monday", "Friday", "Sunday");

boolean anyDayStartWithS = days.stream().anyMatch(s -> s.startsWith("S"));
boolean allStartWithM = days.stream().allMatch(s -> s.startsWith("M"));
boolean noneStartWithY = days.stream().noneMatch(s -> s.startsWith("Y"));

Optional<String> anyString = days.stream().findAny();

Java 8 Streams walkthrough/cheat sheet:

http://files.zeroturnaround.com/pdf/zt_java8_streams_cheat_sheet.pdf

Dokumentatsioon:

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html