Что представляет из себя лямбда функция под капотом

Ответ

Лямбда в Kotlin/Java — это синтаксический сахар для функциональных интерфейсов (SAM). Под капотом:

  1. Для Java: создается анонимный класс, реализующий интерфейс с одним методом (например, Runnable, OnClickListener).
    button.setOnClickListener(v -> { /* code */ });
    // Превращается в:
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) { /* code */ }
    });
  1. Для Kotlin: если лямбда не захватывает переменные, генерируется синглтон-объект для оптимизации. При захвате — создается новый объект при каждом вызове.

Особенности:

  • Нет оверхеда в рантайме (если не захватывает контекст)
  • В Kotlin может быть inline (оптимизация байт-кода)
  • Не является точным аналогом Java 8 лямбд (там используется invokedynamic)

Ответ 18+ 🔞

А, лямбды! Ну, это ж классика, ебушки-воробушки. Смотри, чтобы не охуеть от умных слов, давай на пальцах.

Представь, что тебе надо передать кусок кода как аргумент. Раньше в Яве это была такая пиздопроебибна с анонимными классами — строчек двадцать, где по делу одна. А теперь ты просто пишешь стрелочку -> и всё. Красота!

Под капотом-то что? Ну, там магия, но не особо сложная.

  1. В Яве компилятор видит твою короткую запись и думает: «Ага, чувак, ты хочешь передать действие. Ща я тебе разверну это в полноценный анонимный класс, как в старые добрые». То есть твой красивый код:

    button.setOnClickListener(v -> { /* code */ });

    ...превращается во что-то монструозное, но знакомое:

    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) { /* code */ }
    });

    По сути, синтаксический сахар, да такой сладкий, что диабет заработать можно.

  2. В Котлине ребята пошли дальше. Они такие: «Зачем каждый раз новый объект создавать, если лямбда ничего извне не трогает?». И если твоя лямбда не захватывает переменные из внешней области видимости, то под капотом создаётся один синглтон-объект на всю программу и переиспользуется. Умно, да? А вот если она начинает тащить в себя внешние переменные (это называется «захват контекста»), тогда да, каждый раз будет новый объект. Волнение ебать, но логично.

На что обратить внимание, чтобы не обжечься:

  • Оверхеда в рантайме практически нет, особенно если лямбда «чистая» (ничего не захватывает). Так что не бзди.
  • В Котлине есть супер-фича — inline-функции. Если функцию пометить этим словом, то компилятор не будет генерировать объект для лямбды вообще, а буквально вставит твой код на место вызова. Это овердохуища как эффективно с точки зрения байт-кода.
  • И главное, не путай лямбды Kotlin и Java 8. В Яве восьмой версии для этого используют инструкцию invokedynamic — это уже другая, более низкоуровневая магия виртуальной машины. А в Котлине подход попроще, через объекты. Так что под капотом это разные вещи, хоть снаружи и выглядят похоже.

Короче, инструмент мощный и удобный. Главное — понимать, когда он создаёт объекты, а когда нет, чтобы не получить неожиданностей с производительностью. Но в 99% случаев — да похуй, пиши и радуйся.