Uwolnij moc Java 8: The Ultimate Guide to the Key Features
Java 8 wprowadziła kilka nowych funkcji, które pomogły uczynić ją bardziej wszechstronną i elastyczną. Funkcja Java 8 umożliwia programowanie funkcjonalne . Oto niektóre z kluczowych cech Javy 8:
- Wyrażenia lambda
- Interfejsy funkcjonalne
- Strumień API
- Metody domyślne
- Referencje metody
- Opcjonalny
- Interfejs API daty/godziny
1. Wyrażenia lambda
Za pomocą wyrażeń lambda możemy przedstawić blok kodu, który można później wykonać.
Wyrażenia lambda służą do definiowania funkcji anonimowych , które mogą być przekazywane jako argumenty metod lub mogą być zwracane z metod, tak jak inne obiekty.
Składnia wyrażenia lambda:
(parameters) -> { statements };
Przykłady:
(i) brak argumentów
()-> System.out.println("lambda expression with no arguments");
// lambda expression with one argument
(a) -> System.out.println(String.format("Value of a is: %s", a);
// lambda expression with multiple arguments
(a, b) -> a + b;
// also argument type can be provided explicitely
(Integer a, Integer b) -> a + b;
(Integer a, Integer b) -> { // parentheses needed for multiple statements
System.out.println(String.format("Returning maximum from %s and %s", a, b));
return (a > b) a : b;
};
// functional interface, we will see below in detail
interface MaxFinder {
int findMax(int a, int b);
}
public class LambdaExpressionExample {
public static void main(String[] args) {
// return maximum of two numbers using lambda expression
MaxFinder maxFinder = (a, b) -> (a > b) ? a : b;
System.out.println(maxFinder.findMax(5, 10));
System.out.println(maxFinder.findMax(15, 5));
}
}
Zobaczmy teraz, jak można użyć wyrażenia lambda z pętlą forEach :
public class LambdaExpressionExample {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.forEach(num -> System.out.println(String.format("Square of %s is %s", num, num * num)));
}
}
2. Interfejsy funkcjonalne
Interfejs, który ma dokładnie jedną metodę abstrakcyjną, nazywany jest interfejsem funkcjonalnym , a także nazywany jest interfejsem pojedynczej metody abstrakcyjnej (interfejsy SAM) .
Funkcjonalne interfejsy są podstawą wyrażeń Lambda i umożliwiają pisanie zwięzłego i wyrazistego kodu, eliminując potrzebę anonimowych klas wewnętrznych.
Java 8 zapewnia wiele wbudowanych interfejsów funkcjonalnych, niektóre z nich to Predicate , Function , Consumer i Supplier .
Możesz odwołać się do powyższego prostego przykładu, w którym zdefiniowaliśmy funkcjonalny interfejs MaxFinder .
Adnotacja @FunctionalInterface służy do reprezentowania funkcjonalnego interfejsu.
(i) Predykat
Interfejs predykatów ma pojedynczą metodę abstrakcyjną test(T t) , która przyjmuje pojedynczy argument i zwraca wartość logiczną .
Zwykle jest używany do filtrowania wartości lub do sprawdzania, czy wartość spełnia warunek.
T : typ argumentu wejściowego metody
Oto przykład użycia predykatu :
Predicate<Integer> isEligibleForVoting = (age) -> age >= 18;
boolean eligible = isEligibleForVoting.test(22); // true
Interfejs funkcji ma jedną abstrakcyjną metodę apply(T t) , która przyjmuje jeden argument i zwraca obiekt .
Zasadniczo jest używany do przekształcania lub mapowania wartości z jednego typu na inny.
Oto przykład użycia funkcji :
Function<Integer, Integer> findSquare = (num) -> (num*num);
int square = findSquare.apply(5); // 25
Interfejs konsumenta ma jedną abstrakcyjną metodę accept(T t) , która przyjmuje pojedynczy argument i nie zwraca żadnego wyniku .
Zwykle służy do wykonywania efektów ubocznych, takich jak drukowanie lub logowanie .
Oto przykład użycia Consumer :
Consumer<String> printValue = (x) -> System.out.println(x);
printValue.accept("Java 8 features!"); // prints "Java 8 features!"
Interfejs dostawcy ma jedną abstrakcyjną metodę get(), która nie przyjmuje żadnych argumentów i zwraca wynik .
Zwykle jest używany do leniwej inicjalizacji lub do generowania losowych wartości.
Oto przykład użycia dostawcy:
Supplier<Integer> getRandomInteger = () -> (int) (Math.random() * 500);
int randomInteger = getRandomInteger.get(); // random integer between 0 and 500
public class FunctionalInterfacesExample {
public static void main(String[] args) {
// Using Predicate functional interface
Predicate<Integer> isEligibleForVoting = (age) -> age >= 18;
boolean eligible = isEligibleForVoting.test(22); // true
System.out.println(String.format("Eligible for voting: %s", eligible));
// Using Function functional interface
Function<Integer, Integer> findSquare = (num) -> (num * num);
int square = findSquare.apply(5); // 25
System.out.println(String.format("Square of 5: %s", square));
// Using Consumer functional interface
Consumer<String> printValue = (val) -> System.out.println(val);
printValue.accept("Java 8 features!"); // prints "Java 8 features!"
// Using Supplier functional interface
Supplier<Integer> getRandomInteger = () -> (int) (Math.random() * 500);
int randomInteger = getRandomInteger.get(); // random integer between 0 and 500
System.out.println(String.format("Random number: %s", randomInteger));
}
}
3. Strumieniowe API
Java 8 Stream API to potężne narzędzie do przetwarzania kolekcji danych.
Za pomocą Stream API złożone zadania manipulacji danymi można wykonywać w bardziej zwięzły i wyrazisty sposób niż w przypadku instrukcji warunkowych i tradycyjnych pętli.
Strumień to uporządkowana sekwencja elementów , które mogą być przetwarzane sekwencyjnie lub równolegle .
Za pomocą funkcjonalnych interfejsów i metod możemy tworzyć , przekształcać i przetwarzać strumienie.
Strumień kolekcji można utworzyć za pomocą metody stream() .
Streams API to nowy dodatek do Java Collections Framework, który zapewnia deklaratywny sposób przetwarzania kolekcji obiektów. Strumienie umożliwiają wykonywanie różnych operacji, takich jak filtrowanie , mapowanie i zmniejszanie na kolekcjach obiektów w bardziej zwięzły i czytelny sposób niż tradycyjne pętle for.
Stream API składa się z trzech typów operacji:
(i) Operacje pośrednie:
Operacje pośrednie służą do przekształcania lub filtrowania elementów strumienia.
Zwracają nowy strumień , który dalej może być przetwarzany przez operacje pośrednie lub końcowe .
Najczęściej stosowanymi operacjami pośrednimi są:
- filter() : służy do filtrowania wartości na podstawie warunku
- sorted() : służy do sortowania elementów
- different() : służy do znajdowania odrębnych elementów
- map() : służy do mapowania wartości z jednego typu na inny
Operacje terminalowe służą do generowania końcowego wyniku ze strumienia.
Są one wywoływane po wszystkich operacjach pośrednich , które zostały zastosowane do strumienia.
Najczęściej używane operacje terminalowe to:
- collect() : używany do zwrócenia wyniku operacji pośrednich
- reduce() : służy do redukcji elementów strumienia do jednego elementu.
- forEach() : używany do iteracji przez każdy element w strumieniu
- count() : zwraca liczbę elementów w tym strumieniu
Operacje zwarcia służą do wczesnego uzyskania wyniku, bez przetwarzania całego strumienia.
Operacje pośrednie i terminalowe strumienia Java 8 mogą powodować zwarcie.
Najczęściej używane operacje terminalowe to:
- limit() : używany do zwracania strumienia, gdy tylko osiągnie zadaną wartość graniczną
- anyMatch() : używana do sprawdzania, czy jakiekolwiek elementy tego strumienia pasują do podanego predykatu.
- findFirst() : zwraca Opcjonalny opis pierwszego elementu strumienia lub pusty Opcjonalny, jeśli strumień jest pusty
- findAny() : zwraca Opcjonalne opisujące jakiś element strumienia lub puste Opcjonalne, jeśli strumień jest pusty.
public class StreamAPIExample {
public static void main(String[] args) {
List<Integer> nums = Arrays.asList(3, 1, 4, 2, 6, 8, 5, 7);
System.out.print("Given numbers list: ");
nums.forEach(num -> System.out.print(String.format("%s, ", num)));
System.out.println();
// sort list of numbers
List<Integer> sortedNums = nums.stream().sorted().collect(Collectors.toList());
System.out.print("Sorted numbers are: ");
sortedNums.forEach(num -> System.out.print(String.format("%s, ", num)));
System.out.println();
// filter all numbers less than 6
List<Integer> filteredNums = nums.stream()
.filter(i -> i < 6)
.collect(Collectors.toList());
System.out.print("Numbers less then 5 are: ");
filteredNums.forEach(num -> System.out.print(String.format("%s, ", num)));
System.out.println();
// odd numbers
long oddNumsCount = nums.stream()
.filter(i -> i % 2 == 1).count();
System.out.println(String.format("Total odd numbers are: %s", oddNumsCount));
// print first 2 even numbers found from list while iterating stream
System.out.print("first 2 even numbers found from list while iterating stream: ");
nums.stream()
.filter(num -> num % 2 == 0)
.limit(2)
.forEach(num -> System.out.print(String.format("%s, ", num)));
System.out.println();
// find squares of numbers
List<Integer> squares = nums.stream()
.map(num -> (num * num))
.collect(Collectors.toList());
System.out.print("Squares of numbers are: ");
squares.forEach(square -> System.out.print(String.format("%s, ", square)));
}
}
Dziękujemy za przeczytanie, mam nadzieję, że ta historia pomogła ci w nauce funkcji Java 8.
Proszę śledzić , jeśli podoba Ci się artykuł.
Zapisz się , aby być na bieżąco z nadchodzącymi artykułami.

![Czym w ogóle jest lista połączona? [Część 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































