← Назад к вопросам

В чем разница между Lambda и анонимным классом?

2.0 Middle🔥 221 комментариев
#Stream API и функциональное программирование#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между Lambda и анонимным классом

Лямбда-функции (Java 8+) и анонимные классы решают похожие задачи, но имеют существенные различия в синтаксисе, производительности и функциональности.

Синтаксис

Анонимный класс — громоздко:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        System.out.println("Button clicked");
    }
});

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.length() - b.length();
    }
});

Lambda — компактно:

button.setOnClickListener(v -> System.out.println("Button clicked"));

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, (a, b) -> a.length() - b.length());

Синтаксис Lambda:

// Один параметр, без скобок
s -> s.length()

// Несколько параметров
(a, b) -> a + b

// Без параметров
() -> System.out.println("Hello")

// Несколько строк кода
(a, b) -> {
    int result = a + b;
    return result;
}

// С типами параметров (редко)
(String a, String b) -> a.compareTo(b)

Производительность

Анонимный класс — создаёт новый класс:

// Компилятор создаёт OuterClass$1.class
new Runnable() {
    @Override
    public void run() {
        System.out.println("Test");
    }
};

Каждый анонимный класс — это отдельный файл .class, который загружается в memory.

Lambda — использует invokedynamic:

Runnable r = () -> System.out.println("Test");

Lambda использует механизм invokedynamic (байт-код инструкция), вместо создания отдельного класса. Это:

  • Быстрее загружается
  • Менше памяти
  • Может быть оптимизирована JVM

Область видимости переменных

Анонимный класс может иметь свои переменные:

Runnable r = new Runnable() {
    private int count = 0;  // Своя переменная
    
    @Override
    public void run() {
        count++;  // Изменять свою переменную
        System.out.println(count);
    }
};

Lambda может только читать (final) переменные из окружения:

int count = 0;
Runnable r = () -> {
    System.out.println(count);  // OK — читать
    // count++;  // ❌ Ошибка! Не может изменять
};

// Workaround с массивом
int[] counter = {0};
Runnable r2 = () -> {
    counter[0]++;  // OK — изменяем элемент массива
};

Ключевое слово this

В анонимном классе this указывает на сам класс:

public class Outer {
    public void method() {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(this);  // Вернёт анонимный класс
            }
        };
    }
}

В Lambda this указывает на внешний класс:

public class Outer {
    public void method() {
        Runnable r = () -> {
            System.out.println(this);  // Вернёт Outer инстанс
        };
    }
}

Функциональные интерфейсы

Анонимный класс работает с любым интерфейсом:

public interface CustomInterface {
    void method1();
    void method2();
}

CustomInterface obj = new CustomInterface() {
    @Override
    public void method1() { ... }
    
    @Override
    public void method2() { ... }
};

Lambda работает только с функциональными интерфейсами (один метод):

// ✅ Функциональный интерфейс — одна abstract метод
@FunctionalInterface
public interface Supplier<T> {
    T get();
}

Supplier<String> supplier = () -> "Hello";

// ❌ Не функциональный — две abstract методы
public interface NotFunctional {
    void method1();
    void method2();
}

// Lambda не может быть использована здесь

Практическое сравнение

Фильтрация списка:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Анонимный класс
List<Integer> filtered1 = numbers.stream()
    .filter(new Predicate<Integer>() {
        @Override
        public boolean test(Integer n) {
            return n > 2;
        }
    })
    .collect(Collectors.toList());

// Lambda
List<Integer> filtered2 = numbers.stream()
    .filter(n -> n > 2)
    .collect(Collectors.toList());

Трансформация данных:

// Анонимный класс
List<String> names = numbers.stream()
    .map(new Function<Integer, String>() {
        @Override
        public String apply(Integer n) {
            return "Number: " + n;
        }
    })
    .collect(Collectors.toList());

// Lambda
List<String> names = numbers.stream()
    .map(n -> "Number: " + n)
    .collect(Collectors.toList());

Event Listeners:

// Анонимный класс
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Button pressed");
    }
});

// Lambda
button.addActionListener(e -> System.out.println("Button pressed"));

Когда использовать Lambda?

Lambda лучше для:

  • Простых, одноразовых реализаций
  • Функционального программирования (stream API)
  • Callbacks и event listeners
  • Когда нужна компактность и читаемость
list.forEach(item -> System.out.println(item));
map.forEach((key, value) -> System.out.println(key + ": " + value));
Executor.submit(() -> heavyTask());

Когда использовать анонимный класс?

Анонимный класс лучше для:

  • Интерфейсов с несколькими методами
  • Когда нужна своя состояние (переменные)
  • Когда нужна сложная логика инициализации
  • Когда нужно переопределить несколько методов
new Thread(new Runnable() {
    private int counter = 0;
    
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            counter++;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Counter: " + counter);
    }
}).start();

Таблица сравнения

Аспект              Lambda          Анонимный класс
──────────────────────────────────────────────────
Синтаксис           Компактный      Громоздкий
Производи-          Лучше           Хуже
тельность
Мемория             Меньше          Больше
Функцио-            Только одна      Много методов
нальность
Переменные          Только читать    Свои переменные
Облась видимости    Простая          Сложная
Оптимизация         Хорошая          Стандартная

Lambda в современном коде

// ✅ Современный стиль — используются Lambda
List<User> activeUsers = users.stream()
    .filter(u -> u.isActive())
    .map(u -> u.getName())
    .sorted()
    .collect(Collectors.toList());

// Обработка списков
users.forEach(user -> user.sendEmail());
users.replaceAll(user -> user.withUpdatedDate(LocalDateTime.now()));

// Асинхронное выполнение
CompletableFuture
    .supplyAsync(() -> getData())
    .thenApply(data -> processData(data))
    .thenAccept(result -> displayResult(result));

Вывод

Lambda функции (Java 8+) — это современный способ работы с функциональными интерфейсами. Они:

  • Компактнее — меньше кода, выше читаемость
  • Производительнее — не создают отдельные классы
  • Проще — идеальны для простых реализаций

Анонимные классы остаются полезны для сложных случаев с множественными методами и собственным состоянием. Но в большинстве современного Java кода 8+ версии, Lambda — это предпочтительный выбор.

В чем разница между Lambda и анонимным классом? | PrepBro