Wersja 8 została wydana 18 marca 2014 roku. Wersja do pobrania JDK8.
Zasadnicze zmiany, które weszły wraz z Java 8:
- Wyrażenia lambda
- Interfejs funkcjonalny (functional interface)
- Domyślne i statyczne metody w interfejsach
- Interfejsy funkcjonalne dla:
- Predicate
- Function
- Consumer
- Supplier
- Referencje metod i konstruktorów (method reference, constructor reference) tworzone za przy użyciu operatora ” :: „
- Stream API
- Date and time API
1. Wyrażenia lambda
W Java jest to popularna nazwa dla funkcji anonimowej (Anonymous function) czyli takiej, która nie posiada nazwy, modyfikatora dostępu. Jest definiowana w klasie, która posiada dokładnie jedną instancję.
Kolejnym krokiem jest przypisania nowo utworzonego predykatu do zmiennej np:
W momencie dodania predykatu do zmiennej, która jest wewnątrz metody będzie ona tworzona za każdym razem przy wywołaniu metody. Jeżeli chcemy to zoptymalizować i wywoływać predykat jeden raz przy ładowaniu klasy w pamięci. Możemy zadeklarować zmienną jako static i przenieść ją poza metodę.
Na koniec możemy użyć zmienną isEven w ten sposób:
Jak przejść z klasy anonimowej do funkcji anonimowej?
Doszliśmy więc do tytułu pierwszego działu. Teraz przedstawię składnię wyrażenia lambda:
Następnie powyższe wyrażenie lambda możemy uprościć pozbywając się niepotrzebnych elementów.
I tak w przypadku gdy jest po lewej stronie tylko jeden argument możemy nie pisać nawiasów:
W przypadku używania wyrażenia lambda nie musimy jawnie definiować typów argumentów funkcji. Możliwe jest to dzięki temu, że wyrażenia lambda można używać tylko w miejscach gdzie oczekiwania jest implementacja interfejsu funkcjonalnego. Na tej podstawie Java może wnioskować typy przyjmowane przez interfejs oraz wartości jakie zwróci.
Referencja do metody
Funkcja anonimowa (integer) -> isEven.test(integer) jest równoznacza ze składnią isEven::test, gdzie isEven jest nazwą zmiennej, do której przypisana została metoda, którą chcemy wywołać.
Na koniec można jeszcze zrezygnować z nazwy metody. Nasza nowo utworzona metoda jest w anonimowa:
List<Integer> data = new LinkedList<>(Arrays.asList(3, 1, 6, 2, 9, 0, 5, 4, 8, 7));
System.out.println(Iterables.filter(data, integer -> integer % 2 == 0));
2. Interfejs funkcjonalny (functional interface)
forEach() method in Iterable interface default and static methods in Interfaces Functional Interfaces and Lambda Expressions Java Stream API for Bulk Data Operations on Collections Java Time API Collection API improvements Concurrency API improvements Java IO improvements Miscellaneous Core API improvements
3. Domyślne i statyczne metody w interfejsach
Deklaracja interfejsu „SampleInterf” z zaimplementowaną metodą domyślną:
interface SampleInterf {
default void main() {
log.debug(„default method”);
}
}
implementacja interfejsu:
class Test implements SampleInterf {
public static void main(String[] args) {
Test t = new Test();
t.main();
}
}
Deklaracja interfejsu SampleInterfWithStaticMethod z metodą statyczną. Metodę tego typu możesz używać w praktyce jako klasę narzędziową w pakiecie (utility class). Takiej metody statycznej nie możesz również nadpisywać.
public interface SampleInterfWithStaticMethod {
public static void m() {
System.out.println(„interface with static method”);
}
}
4. Interfejsy funkcjonalne
6. Stream API
Stream jest interfejsem z pakietu java.util.stream. Może przetwarzać każdy obiekt kolekcji (ArrayList, LinkedList, Vector, Stack, PriorityQueue, ArrayDeque, HashSet, LinkedHashSet, TreeSet). Tworzenie streamu wygląda następująco:
Stream s = c.stream();
Jeżeli mamy utworzony Stream możemy nad nim pracować w 2 krokach:
- Konfiguracja
- Filtrowanie (.filter) w przypadku gdy chcemy wybrać interesujące nas pod elementy
- Mapowanie (.map) w przypadku gdy przetwarzamy elementy w Streamie (np. dodajemy)
- Przetwarzanie
src: