Sobes.tech
Middle

Czym są wyrażenia lambda w Java i jakie możliwości one zapewniają?

sobes.tech AI

Odpowiedź od AI

Wyrażenia lambda w Javie to zwięzła składnia do tworzenia funkcji anonimowych (metod bez nazwy), które mogą być przekazywane jako argumenty lub przechowywane w zmiennych. W istocie są to funkcjonalne interfejsy implementowane "na żywo".

Główne możliwości, które zapewniają wyrażenia lambda:

  • Uproszczenie składni: Znacznie skracają kod boilerplate podczas pracy z interfejsami funkcyjnymi w porównaniu z anonimowymi klasami wewnętrznymi.

    // Przed lambdą:
    Runnable classicRunnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("Klasyczny Runnable");
        }
    };
    
    // Z lambdą:
    Runnable lambdaRunnable = () -> System.out.println("Lambda Runnable");
    
  • Programowanie funkcyjne: Pozwalają pisać bardziej funkcyjny kod, gdzie funkcje są obywatelami pierwszej klasy i mogą być przekazywane jako dane. To kluczowy element pracy z API Stream.

    // Filtrowanie listy za pomocą lambda
    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    List<String> filteredNames = names.stream()
                                     .filter(name -> name.startsWith("A"))
                                     .collect(Collectors.toList());
    
  • Praca z API Stream: Wyrażenia lambda są podstawą dla większości operacji w API Stream (filter, map, forEach, reduce itp.), zapewniając zwięzłość i równoległe wykonanie.

    // Transformacja i wyświetlenie elementów strumienia
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    numbers.stream()
           .map(n -> n * n) // lambda do mapowania
           .forEach(System.out::println); // referencja do metody (alternatywa dla lambda)
    
  • Ulepszenie czytelności: Dla prostych operacji lambdy czynią kod bardziej czytelnym i zrozumiałym, skupiając się na samej operacji, a nie na składni anonimowej klasy.

  • Implementacja interfejsów funkcyjnych: Mogą być używane wszędzie tam, gdzie oczekiwany jest egzemplarz interfejsu funkcyjnego (interfejs z jedną metodą abstrakcyjną).

Składnia wyrażenia lambda: (parametry) -> { ciało }

Przykłady:

  • Bez parametrów, bez wartości zwracanej: () -> System.out.println("Cześć")
  • Z jednym parametrem, bez wartości zwracanej: name -> System.out.println("Cześć, " + name) (można pominąć nawiasy wokół pojedynczego parametru)
  • Z wieloma parametrami, bez wartości zwracanej: (x, y) -> System.out.println(x + y)
  • Z parametrami, z wartością zwracaną: (a, b) -> a + b (jeśli ciało składa się z jednej wyrażenia, jego wartość jest domyślnie zwracana)
  • Z parametrami, z blokiem kodu i wartością zwracaną: (a, b) -> { int sum = a + b; return sum; } (wymagane jawne return w blokach kodu)