Любой анонимный класс можно заменить на лямбду

Обновлено: 05.07.2024

Анонимные внутренние классы полезны при написании классов реализации для интерфейсов слушателей в графическом программировании.

Анонимный внутренний класс в основном создается двумя способами:

Синтаксис: синтаксис выражения анонимного класса аналогичен вызову конструктора, за исключением того, что в блоке кода содержится определение класса.

Чтобы понять анонимный внутренний класс, давайте возьмем простую программу

// Java-программа для демонстрации
// нужен анонимный внутренний класс

public static void main(String[] args)

// Myclass - класс реализации интерфейса Age

MyClass obj = new MyClass();

// вызов метода getage (), реализованного в Myclass


// Myclass реализует методы Age Interface

class MyClass implements Age

public void getAge()

System.out.print( "Age is " + x);

Лямбда-выражения :

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

  • Включите, чтобы рассматривать функциональность как аргумент метода или код как данные.
  • Функция, которая может быть создана без принадлежности к какому-либо классу.
  • Лямбда-выражение может передаваться как объект и выполняться по требованию.

// Java-программа для демонстрации лямбда-выражений
// для реализации пользовательского функционального интерфейса.


// Пример функционального интерфейса (Интерфейс с
// один абстрактный метод

Анонимный класс можно заменить на лямбду?

Так что это значит? Что такое лямбда-выражение и как класс Anonymous можно заменить на лямбду?

2 ответа

Аноним нового можно заменить на лямбду?

Это не на 100% правильно, класс Anonymous для интерфейсов, имеющих один абстрактный метод, может быть заменен лямбда-выражением (которое называется функциональным интерфейсом)

поскольку ActionListener есть только один метод actionPerformed(ActionEvent e) Вы можете написать это с помощью лямбда-выражения

Лямбда-выражения

Одна проблема с анонимными классами заключается в том, что если реализация вашего анонимного класса очень проста, например, интерфейс, который содержит только один метод, то синтаксис анонимных классов может показаться громоздким и неясным. В этих случаях вы обычно пытаетесь передать функциональность в качестве аргумента другому методу, например, какое действие следует предпринять, когда кто-то нажимает кнопку. Лямбда-выражения позволяют вам делать это, обрабатывать функциональность как аргумент метода или код как данные.

Поскольку Java8 был недавно выпущен, и его совершенно новые выражения lambda выглядят действительно круто, мне было интересно, означает ли это гибель анонимных классов, к которым мы так привыкли.

Я немного исследовал этот вопрос и нашел несколько интересных примеров того, как выражения Lambda будут систематически заменять эти классы, например метод сортировки коллекции, который использовался для получения анонимного экземпляра Comparator для выполнения сортировки:

Теперь это можно сделать с помощью лямбд:

И выглядит на удивление лаконично. Поэтому мой вопрос заключается в том, есть ли какая-то причина продолжать использовать эти классы в Java8 вместо лямбд?

EDIT

Тот же вопрос, но в противоположном направлении: каковы преимущества использования лямбд вместо анонимных классов, поскольку лямбды могут использоваться только с интерфейсами одного метода, является ли эта новая функция только ярлыком, используемым только в нескольких случаях, или она действительно полезна?

Это из статьи oracle об анонимных классах, которую я читал: Анонимные классы идеально подходят для реализации интерфейса , содержащего два или более методов Я думаю, что это идеально, если вам нужно реализовать менее двух методов, потому что вам не нужно создавать более конкретные именованные.

Название может быть немного запутанным, поэтому позвольте мне уточнить, я читал некоторую критику в отношении Scala. Это было email, отправленное в Tyepsafe по поводу некоторых недостатков в Scala от кода Хейла (архитектора инфраструктуры Yammer) , так сказать: мы перестали воспринимать лямбды как.

Анонимный внутренний класс (AIC) может использоваться для создания подкласса абстрактного класса или конкретного класса. AIC также может обеспечить конкретную реализацию интерфейса, включая добавление состояния (полей). На экземпляр AIC можно ссылаться, используя this в его телах методов, поэтому на нем можно вызывать дополнительные методы, его состояние может изменяться с течением времени и т. Д. Ни одно из них не относится к лямбдам.

Я бы предположил, что большинство применений AICs были предназначены для обеспечения реализации отдельных функций без состояния и поэтому могут быть заменены выражениями lambda, но есть и другие применения AICs, для которых лямбды не могут быть использованы. AICs здесь, чтобы остаться.

UPDATE

Еще одно различие между выражениями AICs и lambda заключается в том, что AICs вводит новую область видимости. То есть имена разрешаются из суперклассов и интерфейсов AIC и могут затенять имена, которые встречаются в лексически замкнутой среде. Для лямбд все имена разрешаются лексически.

Лямбды, хотя и отличная функция, будут работать только с типами SAM. То есть интерфейсы только с одним абстрактным методом. Он потерпит неудачу, как только ваш интерфейс будет содержать более 1 абстрактного метода. Вот где анонимные классы будут полезны.

Итак, нет, мы не можем просто игнорировать анонимные классы. И просто FYI, ваш метод sort() можно упростить, пропустив объявление типа для p1 и p2 :

Вы также можете использовать ссылку на метод здесь. Либо вы добавляете метод compareByFirstName() в класс Person и используете:

Lambda производительность с анонимными классами

При запуске приложения каждый файл класса должен быть загружен и проверен.

Анонимные классы обрабатываются компилятором как новый подтип для данного класса или интерфейса, поэтому для каждого будет создан новый файл класса.

Лямбды отличаются при генерации байт-кода, они более эффективны, используется инструкция invokedynamic, которая поставляется с JDK7.

Для лямбд эта инструкция используется для задержки перевода выражения lambda в байт-коде до выполнения. (инструкция будет вызвана только в первый раз)

В результате выражение Lambda станет статическим методом(созданным во время выполнения). (Существует небольшая разница между случаями состояний и состояний, они разрешаются с помощью сгенерированных аргументов метода)

В Java8 были введены выражения lambda. Этот вопрос касается того, когда выполняются параллельные лямбды. До Java8 вызываемые классы были одним из способов выполнения нескольких потоков одновременно. Вызываемые объекты могут использоваться с исполняемыми классами- исполнителями . Предположим , что.

Можно ли просто добавить лямбды в список операций на диаграмме классов как обычные методы и дать им имя?

Существуют следующие различия:

1) Синтаксис

Lambda выражения выглядят аккуратно по сравнению с анонимным внутренним классом (AIC)

2)Сфера применения

Анонимный внутренний класс-это класс, что означает, что он имеет область действия для переменной, определенной внутри внутреннего класса.

В то время как выражение lambda не является собственной областью, а является частью заключающей области.

Аналогичное правило применяется для ключевого слова super и this при использовании внутри анонимного внутреннего класса и выражения lambda. В случае анонимного внутреннего класса это ключевое слово относится к локальной области, а ключевое слово super относится к суперклассу анонимного класса. В то время как в случае выражения lambda это ключевое слово ссылается на объект заключающего типа, а super будет ссылаться на суперкласс заключающего класса.

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

Во время выполнения анонимные внутренние классы требуют загрузки классов, выделения памяти, инициализации объектов и вызова нестатического метода, в то время как выражение lambda является чистой деятельностью во время компиляции и не требует дополнительных затрат во время выполнения. Таким образом, производительность выражения lambda лучше по сравнению с анонимными внутренними классами.**

**I поймите, что это не совсем верно . Пожалуйста, обратитесь к следующему вопросу для получения более подробной информации. Lambda против анонимной производительности внутреннего класса: снижение нагрузки на ClassLoader?

Lambda в java 8 было введено для функционального программирования. Где вы можете избежать шаблонного кода. Я наткнулся на интересную статью о lambda.

Рекомендуется использовать функции lambda для простой логики. При реализации сложной логики с использованием лямбд будут накладные расходы при отладке кода в случае возникновения проблем.

  • синтаксис lambda не требует написания очевидного кода, который может вывести java.
  • При использовании invoke dynamic lambda не преобразуются обратно в анонимные классы во время компиляции (Java не нужно создавать объекты , просто заботьтесь о сигнатуре метода, можете привязываться к методу без создания объекта
  • lambda уделяйте больше внимания тому, что мы хотим сделать, а не тому, что мы должны сделать, прежде чем сможем это сделать

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

Похожие вопросы:

Мы знаем , что анонимные классы поддерживают ссылку на свой заключающий экземпляр и что это может привести к утечке контекста на Android. Поскольку retrolambda переносит лямбды обратно в Java7.

Мы не можем объявлять конструкторы в анонимных классах. Но если мне нужно инициализировать состояние объектов анонимных классов со значением, скажем, локальных переменных, как бы я это сделал?

Это из статьи oracle об анонимных классах, которую я читал: Анонимные классы идеально подходят для реализации интерфейса , содержащего два или более методов Я думаю, что это идеально, если вам нужно.

Название может быть немного запутанным, поэтому позвольте мне уточнить, я читал некоторую критику в отношении Scala. Это было email, отправленное в Tyepsafe по поводу некоторых недостатков в Scala.

В Java8 были введены выражения lambda. Этот вопрос касается того, когда выполняются параллельные лямбды. До Java8 вызываемые классы были одним из способов выполнения нескольких потоков одновременно.

Можно ли просто добавить лямбды в список операций на диаграмме классов как обычные методы и дать им имя?

В одном из аргументов о различиях между лямбдами и анонимными классами, в этом посте: Java8 лямбды против анонимных классов Я читал утверждение, что Lambdas can have state точно так же, как.

Если вы поищете java double brace, то найдете веские аргументы против его использования. Каждый раз, когда кто-то использует инициализацию двойной скобки, котенка убивают.

Просматривая выражения lambda, я наткнулся на приведенное ниже поведение для анонимных внутренних классов и выражений lambda. Что может быть причиной этого? Human h = new Human() < int a = 2;.

Язык программирования Java позволяет объявлять классы внутри другого класса. Такой класс называется вложенным классом:

Вложенные классы бывают статическими и нестатическими. Вложенные классы, объявленные с ключевым словом static , называются статическими вложенными классами (static nested classes). Вложенные классы, объявленные БЕЗ ключевого слова static, называются внутренними классами (inner classes).

Вложенный класс является членом класса, в который он вложен. Внутренние классы имеют доступ к членам класса, в который они вложены, даже если эти члены объявлены с модификатором private , для этого компилятор создаёт специальные методы доступа к этим полям, так что сама виртуальная машина принципов ООП не нарушает.

Как члены класса вложенные классы могут быть объявлены с ключевым словом private , protected , public или без модификатора доступа (package-private).

Внешний класс (OuterClass) может быть только public или package-private!

Для чего использовать вложенные классы

Причины для использования вложенных классов в Java:

  • Логическая группировка классов, которые используются только в одном месте. Если класс используется только одним другим классом, то есть смысл вложить его в этот класс, чтобы обозначить их связь.
  • Увеличение инкапсуляции. Если класс B должен обращаться к членам класса A , которые в противном случае были бы объявлены private , то имеет смысл вложить класс B в класс A , тогда эти члены можно будет объявить private , но B сможет к ним обращаться. В дополнение B можно будет скрыть от внешнего мира.
  • Облегчение чтения и сопровождения кода. Маленькие классы можно вложить во внешние классы, ближе к месту использования.

Статические вложенные классы

Статические вложенные классы связаны со своим внешним классом так же, как методы и переменные.

И так же как и статические методы они не могут обращаться к переменным экземпляров и методам экземпляров внешнего класса, в который они вложены, напрямую, они могут обращаться к ним только через ссылку на объект. Через ссылку на объект они могут обращаться к членам экземпляров внешнего класса независимо от их модификатора доступа.

Статические вложенные классы могут обращаться к static членам класса, в который они вложены, с любым модификатором доступа.

К статическим вложенным классам обращаются через имя их внешнего класса:

Либо можно импортировать статический вложенный класс и обращаться к нему по имени:

Внутренние классы бывают:

  • Нестатическими членами класса.
  • Локальными классами.
  • Анонимными классами.

Хотя сериализация конструкций с внутренними классами возможна, но на практике строго НЕ рекомендуется так делать. Для работы с внутренними классами компилятор создаёт синтетические конструкции, которые могут сильно отличаться в различных реализациях компиляторов.

Внутренний класс, являющийся нестатическим членом класса

Внутренний класс будет нестатическим членом класса, если он объявлен прямо внутри тела внешнего класса:

Такие внутренние классы обычно обычно логически связаны со своим внешним классом. Они имеют доступ ко всем полям этого внешнего класса. Экземпляры этих классов могут создаваться внутри внешнего класса и, при достаточном уровне доступа, другими классами из других пакетов.

Нестатические вложенные классы, являющиеся членами класса, могут быть объявлены с любым из модификаторов private , protected , public или без модификатора (package-private).

Локальные классы

Локальным классом называется класс, который не является членом какого-либо другого класса и имеет имя.

Локальные классы не могу иметь никаких модификаторов доступа: ни private , ни protected , ни public .

Анонимные классы

Анонимные классы объявляются внутри выражения с ключевым словом new . Пример:

Выражение анонимного класса состоит из:

  • Операции new .
  • Имени интерфейса для реализации или родительского класса. В данном примере используется интерфейс MyInterface .
  • Скобки с аргументами для конструктора родительского класса. Анонимный класс не может объявить в своём теле новых конструкторов, так как у него нет имени.
  • Тело класса.

Анонимный класс никогда не может быть abstract (абстрактные классы будут рассмотрены позже).

Анонимный класс всегда неявно final .

Анонимные классы могут обращаться к переменным метода, в котором они объявлены, если эти переменные объявлены как final , или они final по действию, то есть фактически не меняются.

Затенение переменных

Если имя переменной в какой-либо области имеет такое же имя, что и переменная во внешней области, то такая переменная затеняет (shadow) переменную из внешней области. Вы не можете обратиться к переменной из внешней области просто по имени. Пример ниже показывает, как нужно обращаться к затенённой переменной:

Простой пример использования лямбда-выражения:

Так же как и локальные и анонимные классы лямбда-выражения могут обращаться к локальным переменным своей области, если эти переменные объявлены final или являются final по действию. Лямбда-выражения в Java не порождают новую область видимости переменных, они используют ту же область, что и метод.

Так как лямбда-выражения используют ту же область видимости переменных, что и метод, в котором они объявлены, то они не могут вызывать затенения (shadow) переменных. Если в коде выше мы объявим лямбда-выражение так:

То будет ошибка компиляции, так как переменная x в этой области уже объявлена.

Тип результата у лямбда-выражения будет такой, какой ожидается в этом месте, поэтому лямбда-выражения можно использовать только там, где компилятор Java может определить его тип:

  • Объявления переменных.
  • Операции присвоения.
  • Операторы return .
  • Инициализации массивов.
  • Аргументы конструкторов или методов.
  • Тела лямбда-выражений.
  • условные операторы, ? : .
  • Выражения приведения типа.

Лямбда-выражения можно сериализовать, если его аргументы и результат сериализуемые, однако так делать строго НЕ рекомендуется.

Пакет java . util . function содержит большое количество стандартных интерфейсов, которые специально предназначены для использования с лямбда-выражениями. Хотя в примерах выше мы всегда создавали свой интерфейс, но в реальных приложениях рекомендуется использовать подходящий стандартный интерфейс, который можно поискать в документации. Все интерфейсы там обобщённые (статья про обобщение в Java будет написана позже), и могут использоваться с любым объектом.

Некоторые из функциональных интерфейсов пакета java . util . function :

Consumer — содержит один метод с одним объектом в качестве параметра без результата метода.

Function T , R > — содержит один метод с одним объектом в качестве параметра, возвращающий другой объект в качестве результата.

Predicate — содержит один метод с объектом в качестве параметра, возвращающий результат boolean .

Supplier — содержит один метод без параметров, возвращающий объект.

Ссылки на методы

Если лямбда-выражение выполняет только вызов определённого метода или конструктора, то вместо него можно использовать ссылку на метод.

Лямбда-выражение Java, Лямбда-выражение Java, Лямбда-выражения Java 8, учебник по лямбда-выражению java, пример лямбда-выражения java, лямбда-функция java, Лямбда-выражение на Java.

Лямбда-выражение Java можно считать одной из самых крутых функций, представленных в Java 8 . Это первый шаг Java в функциональном программировании. Лямбда-выражение Java можно рассматривать как функцию, которая может быть создана без принадлежности к какому-либо классу. Кроме того, его можно передавать как объект и выполнять по требованию.

Лямбда-выражение Java

По сути, лямбда-выражение-это краткое представление анонимной функции, которую можно передавать. Таким образом, он обладает следующими свойствами:

  • Анонимный : Мы можем сказать анонимный, потому что у него нет явного имени, как обычно у метода. Так что писать и думать об этом определенно меньше.
  • Функция : Ее можно рассматривать как функцию, потому что лямбда-выражение не связано с определенным классом, как метод. Но, как и метод, лямбда-код содержит список параметров, тело, тип возвращаемого значения и возможный список исключений, которые могут быть вызваны.
  • Передано : Лямбда-выражение может быть передано в качестве аргумента методу или сохранено в переменной.
  • Краткий : Нам не нужно писать много шаблонных шаблонов, как мы делаем для анонимных классов.

Технически лямбда-выражения не позволяют нам делать ничего такого, чего мы не делали до Java 8. Просто нам не нужно писать неуклюжий код, чтобы использовать параметризацию поведения.

Пример Лямбда-выражения Java

Пример, безусловно, поможет получить четкое представление. Рассмотрим Яблоко класс:

Если мы хотим написать пользовательский компаратор для сравнения яблок по весу, до Java 7 мы писали его следующим образом:

Теперь, используя лямбда-выражение, мы можем написать то же самое, что:

Объяснение Лямбда-выражения Java

Давайте углубимся в отдельные фрагменты этого выражения:

  • Список параметров : В этом случае он отражает параметры метода сравнения Компаратора – двух объектов Apple.
  • Стрелка : Стрелка -> отделяет список параметров от тела лямбды.
  • Тело лямбды : Сравните два яблока, используя их вес. Выражение считается возвращаемым значением лямбды.

Использование лямбда-выражения Java 8

Давайте рассмотрим некоторые примеры использования лямбда-выражения java.

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

Очевидно, возникает вопрос, где разрешены такие выражения? Ранее мы видели лямбда-выражение, заменяющее реализацию компаратора. мы также можем использовать его следующим образом:

Здесь метод filter() ожидает Предикат . Мы просто передали лямбду вместо требуемого интерфейса.

В принципе, мы можем использовать их в контексте функциональных интерфейсов . Итак, что же такое Функциональные интерфейсы?

В двух словах, Функциональный интерфейс-это интерфейс, который определяет ровно один абстрактный метод.

Некоторыми известными функциональными интерфейсами в Java являются Компаратор , Запускаемый , Список действий , Вызываемый и т. Д.

Также обратите внимание, что интерфейс по-прежнему является функциональным интерфейсом, даже если он определяет один или несколько методов по умолчанию, если он определяет один абстрактный метод.

И, конечно, мы всегда можем определить пользовательские функциональные интерфейсы, отличные от интерфейсов по умолчанию, предоставляемых Java.

Лямбда-выражения Java позволяют нам предоставлять реализацию абстрактного метода функционального интерфейса напрямую, встроенно, и все выражение рассматривается как экземпляр конкретной реализации этого интерфейса.

Лямбда-выражения Java против анонимного класса

Учитывая наши предыдущие примеры, того же самого можно достичь и с помощью анонимного класса, но код будет более неуклюжим, если мы будем писать реализацию встроенно.

Давайте рассмотрим пример запускаемого . Рассмотрим процесс метод, который принимает Выполняемый экземпляр:

Без использования Лямбды мы можем реализовать его как:

Использование лямбда – выражения:

Кроме того, в тех случаях, когда мы используем эту выполняемую реализацию только один раз, мы также можем предоставить ее непосредственно при вызове метода process:

Дескриптор функции

Важная вещь, которую необходимо понимать при работе с лямбда-выражением, – это функциональный дескриптор. Сигнатура абстрактного метода функционального интерфейса по существу описывает сигнатуру лямбда – выражения. Мы называем этот абстрактный метод дескриптором функции.

Например, выполняемый интерфейс можно рассматривать как подпись функции , которая ничего не принимает и ничего не возвращает (void), поскольку у нее есть только один абстрактный метод с именем run , который ничего не принимает и ничего не возвращает (void).

Читайте также: