Ah! Co to był za wrzesień, niedawno premierę miała nowa wersja biblioteki JUnit 5, a teraz mamy oficjalne wydanie Javy 9. Dziewiątka nie jest tak przełomową wersją Javy jak ósemka, jednakże wprowadza kilka ciekawych featurów i usprawnień. W tym wpisie bierzemy na tapetę Stream API.
takeWhile/dropWhile
Operacje na nieskończonych strumieniach są teraz ułatwione, w przykładzie poniżej zostaną wypisane tylko trzy napisy, natomiast program będzie się wykonywał dalej w nieskończoność:
Stream.iterate(“”, s -> s + “s”)
.filter(s->s.length() < 3)
.forEach(this::log);
W nowym API dostajemy dwie metody:
takeWhiledropWhile
Służą one do “obcinania” strumieni. W pierwszy przypadku zostaną wypisane tylko trzy napisy i strumień się zamknie. W drugim przypadku będą wyświetlane wszystkie napisy, których długość jest większa od trzy:
Stream.iterate(“”, s -> s + “s”)
.takeWhile(s->s.length() < 3)
.forEach(this::log);
Stream.iterate(“”, s -> s + “s”)
.dropWhile(s->s.length() < 3)
.forEach(this::log);
iterate
Przykład podobny do tego powyżej. Metoda iterate ma teraz swoją trójargumentową wersję. Chcemy wypisać 10 liczb po kolei:
Stream.iterate(0, i -> i < 10, i -> i + 1)
.forEach(this::log);
No dobra, ale w Javie 8 mogliśmy zrobić coś takiego:
Stream.iterate(0, i -> i + 1)
.limit(10)
.forEach(this::log);
Ale teraz wyobraźmy sobie, że mamy bardziej skomplikowany obiekt, na przykład wypisz mi wszystkie daty od początku roku do dziś:
Stream.iterate(startDate, date -> date.plusDays(1))
.filter(date->date.isBefore(LocalDate.now()))
.forEach(this::log); // To wypisze nam wszystkie daty do dziś, ale strumień będzie się dalej “kręcił”
Stream.iterate(startDate, date -> date.plusDays(1))
.peek(this::log)
.allMatch(date->date.isBefore(LocalDate.now())); // Działający przykład, mniej intuicyjny
W Javie 9 możemy użyć trójargumentowego iterate:
Stream.iterate(startDate,date -> date.isBefore(LocalDate.now()), date -> date.plusDays(1))
.forEach(this::log);
ofNullable
Kolejny przykład to metoda ofNullable. Działa ona tak samo jak ofNullable w Optional (nie musimy sprawdzać, czy element jest nullem i wstawiać Stream.empty()):
Map<String, Integer> map = new HashMap<>();
map.put(“String”, 1);
map.put(“StringSecond”, null);
//JAVA 8
List
.flatMap(element -> {
Integer temp = map.get(element);
return temp != null ? Stream.of(temp) : Stream.empty();
})
.collect(toList());
//JAVA 9
List
.flatMap(element -> Stream.ofNullable(map.get(element)))
.collect(toList());
Stream z Optional
Ostatnim usprawnieniem jest dodanie metody, która pozwala z Optional’a stworzyć Stream. Bo tak naprawdę Optional to dwa elementy: null lub wartość. Od teraz nie trzeba wykonywać operacji sprawdzania, czy element istnieje tylko od razu można wykorzystać flatMap:
@Test
void streamFromOptional(){
//JAVA 8
Stream.of(“string”, “second”)
.map(this::getSomething)
.filter(Optional::isPresent)
.map(Optional::get)
.forEach(this::log);
//JAVA 9
Stream.of("string", "second")
.map(this::getSomething)
.flatMap(Optional::stream)
.forEach(this::log);
}
Optional
return text.equals(“second”) ? Optional.of(text) : Optional.empty();
}
Github
Całość jak zawsze na GitHubie.
