Лямбды
Лямбда — это короткая запись функции, которую можно передать как аргумент. До Java 8 чтобы передать «действие» в метод, нужно было написать анонимный класс — громоздко и многословно. Лямбда делает то же самое в одну строку.
// Раньше — анонимный класс
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Привет");
}
};
// С лямбдой — то же самое
Runnable r = () -> System.out.println("Привет");
Синтаксис лямбды: (параметры) -> тело
() -> System.out.println("нет параметров")
x -> x * 2 // один параметр — скобки необязательны
(x, y) -> x + y // два параметра
(String s) -> s.length() > 3 // с типом параметра
(x, y) -> { int r = x + y; return r; } // несколько строк — блок с return
Method reference — ещё короче, когда лямбда просто вызывает существующий метод:
.map(name -> name.toUpperCase()) // лямбда
.map(String::toUpperCase) // то же — method reference
.forEach(s -> System.out.println(s))
.forEach(System.out::println) // то же
.sorted((a, b) -> a.compareTo(b))
.sorted(String::compareTo) // то же
Копнуть глубже
Четыре вида method reference:
// 1. Статический метод
.map(Integer::parseInt) // Integer.parseInt(s)
// 2. Метод экземпляра через тип (первый параметр становится получателем)
.map(String::toUpperCase) // s.toUpperCase()
// 3. Метод конкретного экземпляра
String prefix = "Hello";
.map(prefix::concat) // prefix.concat(s)
// 4. Конструктор
.map(User::new) // new User(s)
Захват переменных (closure). Лямбда может использовать переменные из окружающего контекста, но они должны быть effectively final — не меняться после присваивания (явный final не обязателен):
String greeting = "Привет"; // effectively final
names.forEach(name -> System.out.println(greeting + ", " + name)); // ✅
greeting = "Здравствуй"; // ❌ теперь не effectively final → не скомпилируется
Почему effectively final? Лямбда может выполниться в другом потоке или позже — если бы переменная менялась, поведение было бы непредсказуемым. JVM «захватывает» значение в момент создания лямбды, а не ссылку на переменную.
Лямбды не создают анонимный класс. В отличие от анонимных классов, лямбды реализованы через invokedynamic (JVM-инструкция) — это быстрее, меньше классов в памяти, и this внутри лямбды ссылается на объемлющий класс (а не на саму лямбду, как в анонимном классе).
• четыре вида method reference и что такое effectively final (если дошёл до 2-го слоя).