Narzędzia Informatyki

Opis zajęć i zasad

Java 8 Stream

Strumienie są odpowiedzią języka java na potrzebę tworzenia kodu umożliwiającego przetwarzanie równoległe. Java 8 Streams API udostępnia mechanizm przetwarzania kolekcji w Javie (np. Listy, Mapy, Sety). Podstawową ideą jest zamiana kolekcji w strumień danych, równoległe przetwarzanie tego strumienia i zbieraniu wyników tego przetwarzania na powrót w kolekcję danych.

Strumienie

Interfejs strumieni jest zdefiniowany w pakiecie java.util.stream. Od Javy 8 kolekcje posiadają metody zwracające strumienie. Podobnie do języków funkcyjnych strumienie wspierają operacje agregacji. Najpowszechniejsze operacje agregacji to filter, map, reduce, find, match, sort. Operacje te mogą być uruchamiane sekwencyjnie lub równolegle.

Jako wynik strumień może zwracać kolejny strumień. Metodę tworzenie łańcuchów strumieni, gdzie każdy poprzedni zwraca wejście do kolejnego nazywamy pipelining (montaż rurociągów).

Tradycyjnie w Javie do przechodzenia po kolkcjach korzystamy z iteratorów jawnie wyspecyfikowanych w kodzie:

List<String> names = new ArrayList<>();
for (Student student : students) {
        if(student.getName().startsWith("A")){
        names.add(student.getName());
        }
}

Wykorzystując strumienie korzystamy z tzw. wewnętrznych iteracji, to znaczy logika iteracji po elementach jest dla nasz ukryta a skupiamy się na ich przetwarzaniu.

List<string> names = students.stream()
                .map(Student::getName)
                .filter(name->name.startsWith("A:)
                .collect(Collectors.toList());

Operacje na strumieniach

Operacja na strumieniach dzielimy na pośrednie i końcowe (terminalne). Operacje pośrednie zwracają jako wynik działania strumień. W powyższym przykładzie takimi operacjami są map,filter i limit. Operacje terminalne kończą przetwarzanie, zwykle agregują one wyniki, zliczają wartości, albo też nic nie wykonują (np. operacja foreach może być terminalna).

Dla operacji numerycznych stworzono specjalne strumienie IntStream, DobuleStream, and LongStream.

IntStream.rangeClosed(1, 10).forEach(num -> System.out.print(num));
// ->12345678910
IntStream.range(1, 10).forEach(num -> System.out.print(num));
// ->123456789

Budowa strumieni

Stream stałych i elementów tablicy:

Stream.of("This", "is", "Java8", "Stream").forEach(System.out::println);
String[] stringArray = new String[]{"Streams", "can", "be", "created", "from", "arrays"};
Arrays.stream(stringArray).forEach(System.out::println);

Elementy strumieni

Map

Zmienia przetwarzany element na coś innego, czyli pobiera element jednego typu i zwraca element innego typu. W praktyce najczęściej służy do wyciągnięcia jakiś atrybutów z obiektów.

students.stream()
        .map(Student::getName)
        .forEach(System.out::println);

The Student::getName jest skrótowym odwołaniem się do metody z klasy. Czyli na obiekcie typu Student, który przyjdzie ze streama wywołujemy metodę getName().

FlatMap

Działa podobnie jak mapa, tylko jako wynik zwraca strumień przetworzonych elementów.

List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
List<List<Integer>> mapped =
                                numbers.stream()
                                .map(number -> Arrays.asList(number -1, number, number +1))
                                .collect(Collectors.toList());

System.out.println(mapped); //:> [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5]]

List<Integer> flattened =
                                numbers.stream()
                                .flatMap(number -> Arrays.asList(number -1, number, number +1).stream())
                                .collect(Collectors.toList());
System.out.println(flattened);  //:> [0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5]

.

Filter

Wybiera elementy ze strumienia względem danego warunku

students.stream()
                .filter(student -> student.getScore() >= 60)
                .collect(Collectors.toList());

.

Distinct

Usuwa powtórzenia

students.stream()
                .map(Student::getName)
                .distinct()
                .collect(Collectors.toList());

.

Limit

Ogranicza liczbę elementów w strumieniu do podanej liczby.

Sorted

Sortuje elementy w naturalnym dla nich porządku.

students.stream()
                .map(Student::getName)
                .sorted()
                .collect(Collectors.toList());

Z pomocą klasy Comparator możemy definiować sortowania różnego typu

//Sorting names if the Students in descending order
students.stream()
                .map(Student::getName)
                .sorted(Comparator.reverseOrder())
                .collect(Collectors.toList());
//Sorting names if the Students in descending order
students.stream()
                .map(Student::getName)
                .sorted(Comparator.reverseOrder())
                .collect(Collectors.toList());
//Sorting students by First Name and Last Name both
students.stream()
                .sorted(Comparator.comparing(Student::getFirstName).
                                thenComparing(Student::getLastName))
                .map(Student::getName)
                .collect(Collectors.toList());
//Sorting students by First Name Descending and Last Name Ascending
students.stream()
                .sorted(Comparator.comparing(Student::getFirstName)
                                .reversed()
                                .thenComparing(Student::getLastName))
                .map(Student::getName)
                .collect(Collectors.toList());

Elementy Terminalne

Match

Match stosujemy gdy interesuje nas występowanie w strumieniu elementu o danych własnościach.

//Check if at least one student has got distinction
Boolean hasStudentWithDistinction = students.stream()
                .anyMatch(student -> student.getScore() > 80);

//Check if All of the students have distinction
Boolean hasAllStudentsWithDistinction = students.stream()
                .allMatch(student -> student.getScore() > 80);

//Return true if None of the students are over distinction
Boolean hasAllStudentsBelowDistinction = students.stream()
                .noneMatch(student -> student.getScore() > 80);

.

Find

Pozwala znajdować obiekt w strumieniu o danych włanościach, możemy wybrać dowolny dopasowany obiekt lub pierwszy dopasowany.

//Returns any student that matches to the given condition
students.stream().filter(student -> student.getAge() > 20)
                        .findAny();
//Returns first student that matches to the given condition
students.stream().filter(student -> student.getAge() > 20)
                        .findFirst();

.

Reduce

Pozwala zredukować strumień danych do pojedynczej wartości.

//Summing without passing an identity
Optional<integer> sum = numbers.stream()
                .reduce((x, y) -> x + y);
//Product without passing an identity
Optional<integer> product = numbers.stream()
                .reduce((x, y) -> x * y);

.

Collect

Zbiera elementy strumienia w listę.

Przykłady

Mała ściąga dotycząca strumieni

Przykłady po Polsku

Więcej przykładów po Angielsku

Zadanie Domowe (10pkt)

Ściągnij kod:

Plik

Otwórz kod w środowisku IntelliJ IDEA.

Wybierz open project i wybierz pierwszy katalo nad src.

Wybierz View->Tools->Maven

a5

KLiknij odśwież (dwie zielone strzałeczki a następnie zaznacz compile i wybierz Play (zielony trójkącik)).

a1

Następnie w okienku project manadżera po lewej stronie znajdź katalog test a w nim plik TestNIF.java kliknij prawym na tym pliku i wybierz Run...

Uruchomią się testy, i wszystkie pokażą błędy. Twoim celem jest osiągnięcie stanu w którym wszystkie testy zakończą się poprawnie.

Aby testy wykonały się poprawnie musisz dopisać strumienie w plikach z katalogu src. W każdym z nich znajduje się metoda napisana w "starej" Javie i pusta metoda w której Twoim zadaniem jest dopisać strumień zachowujący się tak samo jak podana już metoda. Testy powiedzą Ci czy osiągnąłeś sukces.

Kod Java proszę przesłać przez stronę:

Termin wykonania zadania: Czwartek 16.06.2017 do godziny 24.00.

*

Wykorzystano materiały z:

http://java.amitph.com/2014/01/understanding-java-8-streams-api.html

https://github.com/vfarcic/java-8-exercises/

http://www.w3ii.com/pl/java8/java8_streams.html

http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/

https://blog.idrsolutions.com/2014/11/java-8-streams-explained-5-minutes/

https://zeroturnaround.com/rebellabs/java-8-streams-cheat-sheet/

http://java.amitph.com/2014/02/java-8-streams-api-intermediate.html

http://java.amitph.com/2014/02/java-8-streams-api-terminal-operations.html