Поскольку Java8 была недавно выпущена и ее новые лямбда-выражения выглядят действительно круто, мне было интересно, означает ли это кончину анонимных классов, к которым мы так привыкли.
Я немного исследовал это и нашел несколько классных примеров того, как лямбда-выражения будут систематически заменять эти классы, например метод сортировки Collection, который используется для получения анонимного экземпляра Comparator для выполнения сортировки:
Collections.sort(personList, new Comparator<Person>(){
public int compare(Person p1, Person p2){
return p1.firstName.compareTo(p2.firstName);
}
});
Теперь это можно сделать с помощью лямбда-выражений:
Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));
И выглядит на удивление лаконично. Итак, мой вопрос: есть ли причина продолжать использовать эти классы в Java8 вместо Lambdas?
РЕДАКТИРОВАТЬ
Тот же вопрос, но в противоположном направлении, каковы преимущества использования Lambdas вместо анонимных классов, поскольку Lambdas можно использовать только с интерфейсами с одним методом, эта новая функция только ярлык используется только в нескольких случаях или действительно полезна?
источник
Comparator.comparing(Person::getFirstName)
ifgetFirstName()
будет возвращающим методомfirstName
.Ответы:
Анонимный внутренний класс (AIC) может использоваться для создания подкласса абстрактного класса или конкретного класса. AIC также может предоставлять конкретную реализацию интерфейса, включая добавление состояния (полей). На экземпляр AIC можно ссылаться, используя
this
его тела методов, поэтому для него могут быть вызваны дополнительные методы, его состояние может изменяться с течением времени и т. Д. Ничего из этого не применимо к лямбдам.Я предполагаю, что в большинстве случаев AIC используются для реализации отдельных функций без сохранения состояния и поэтому могут быть заменены лямбда-выражениями, но есть и другие варианты использования AIC, для которых лямбда-выражения не могут использоваться. AIC здесь, чтобы остаться.
ОБНОВИТЬ
Еще одно различие между AIC и лямбда-выражениями заключается в том, что AIC вводят новую область видимости. То есть имена разрешаются из суперклассов и интерфейсов AIC и могут скрывать имена, встречающиеся в лексически включающей среде. Для лямбда-выражений все имена разрешаются лексически.
источник
A$1.class
а Lambda - нет. Могу я добавить это в Разницу?LambdaClass$$Lambda$1/1078694789
. Однако этот класс генерируется «на лету» метафакторией лямбда-выражения, а не byjavac
, поэтому соответствующего.class
файла нет. Опять же, это проблема реализации.Lambdas - отличная функция, но работает только с типами SAM. То есть взаимодействует только с одним абстрактным методом. Он не сработает, если ваш интерфейс будет содержать более одного абстрактного метода. Вот здесь и пригодятся анонимные классы.
Итак, мы не можем просто игнорировать анонимные классы. И, к вашему сведению, ваш
sort()
метод можно упростить, пропустив объявление типа дляp1
иp2
:Вы также можете использовать здесь ссылку на метод. Либо вы добавляете
compareByFirstName()
метод вPerson
класс, и используете:или, добавьте геттер для
firstName
, напрямую получите методComparator
fromComparator.comparing()
:источник
new @MyTypeAnnotation SomeInterface(){};
. Это невозможно для лямбда-выражений. Подробнее см. Мой вопрос здесь: Аннотирование функционального интерфейса лямбда-выражения .Производительность лямбда с анонимными классами
При запуске приложения каждый файл класса должен быть загружен и проверен.
Анонимные классы обрабатываются компилятором как новый подтип для данного класса или интерфейса, поэтому для каждого будет создан новый файл класса.
Лямбда-выражения отличаются при генерации байт-кода, они более эффективны, используются инструкции invokedynamic, которые идут с JDK7.
Для лямбда-выражений эта инструкция используется для задержки преобразования лямбда-выражения в байт-код до времени выполнения. (инструкция будет активирована только в первый раз)
В результате лямбда-выражение станет статическим методом (созданным во время выполнения). (Есть небольшая разница с состояниями и состояниями с полным состоянием, они разрешаются через сгенерированные аргументы метода)
источник
invokedynamic
что обычно медленнее, чемinvokespecial
при создании новых экземпляров анонимных классов. Таким образом, в этом смысле лямбды тоже медленнее (однако JVMinvokedynamic
большую часть времени может оптимизировать вызовы).invokedynamic
создание специальных классов происходит очень быстро по сравнению со скомпилированными анонимными классами.Различают следующие отличия:
1) Синтаксис
Лямбда-выражения выглядят аккуратно по сравнению с анонимным внутренним классом (AIC)
2) Объем
Анонимный внутренний класс - это класс, что означает, что у него есть область видимости для переменной, определенной внутри внутреннего класса.
Принимая во внимание, что лямбда-выражение не является отдельной областью действия, но является частью охватывающей области.
Аналогичное правило применяется для ключевого слова super и this при использовании внутри анонимного внутреннего класса и лямбда-выражения. В случае анонимного внутреннего класса это ключевое слово относится к локальной области видимости, а ключевое слово super относится к суперклассу анонимного класса. В то время как в случае лямбда-выражения это ключевое слово относится к объекту включающего типа, а super будет относиться к суперклассу включающего класса.
3) Производительность
Во время выполнения анонимные внутренние классы требуют загрузки класса, выделения памяти и инициализации объекта и вызова нестатического метода, в то время как лямбда-выражение - это чистая операция времени компиляции и не требует дополнительных затрат во время выполнения. Таким образом, производительность лямбда-выражения лучше по сравнению с анонимными внутренними классами. **
** Я понимаю, что это не совсем так. Пожалуйста, обратитесь к следующему вопросу для получения подробной информации. Лямбда против анонимной производительности внутреннего класса: снижение нагрузки на ClassLoader?
источник
Лямбда в java 8 была введена для функционального программирования. Где можно избежать шаблонного кода. Я наткнулся на эту интересную статью о лямбдах.
http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html
Для простой логики желательно использовать лямбда-функции. Если реализовать сложную логику с использованием лямбда-выражений, это приведет к накладным расходам при отладке кода в случае возникновения проблемы.
источник
Анонимный класс должен остаться, потому что лямбда хороша для функций с одними абстрактными методами, но для всех остальных случаев анонимные внутренние классы - ваш спаситель.
источник
invoke dynamic
, лямбда не преобразуются обратно в анонимных классов во время компиляции (Java не должен пройти через создание объектов, просто заботиться о подписи методы, можно привязать к методу без создания объектаисточник