Java8 Lambdas против анонимных классов

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

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

Collections.sort(personList, new Comparator<Person>(){
  public int compare(Person p1, Person p2){
    return p1.firstName.compareTo(p2.firstName);
  }
});

Теперь можно использовать Lambdas:

Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));

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

ИЗМЕНИТЬ

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

Ответ 1

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

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

ОБНОВИТЬ

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

Ответ 2

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

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

Collections.sort(personList, (p1, p2) -> p1.firstName.compareTo(p2.firstName));

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

Collections.sort(personList, Person::compareByFirstName);

или, добавьте getter для firstName, непосредственно получите Comparator из Comparator.comparing() метод:

Collections.sort(personList, Comparator.comparing(Person::getFirstName));

Ответ 3

Производительность лямбда с анонимными классами

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

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

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

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

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

Ответ 4

Существуют следующие отличия:

1) Синтаксис

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

public static void main(String[] args) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("in run");
        }
    };

    Thread t = new Thread(r);
    t.start(); 
}

//syntax of lambda expression 
public static void main(String[] args) {
    Runnable r = ()->{System.out.println("in run");};
    Thread t = new Thread(r);
    t.start();
}

2) Область

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

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

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

//AIC
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = new Runnable() {
            @Override
            public void run() {
                int cnt = 5;    
                System.out.println("in run" + cnt);
            }
        };

        Thread t = new Thread(r);
        t.start();
    }

//Lambda
    public static void main(String[] args) {
        final int cnt = 0; 
        Runnable r = ()->{
            int cnt = 5; //compilation error
            System.out.println("in run"+cnt);};
        Thread t = new Thread(r);
        t.start();
    }

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

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

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

Ответ 5

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

http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html

Целесообразно использовать лямбда-функции для простых логик. Если реализовать сложную логику с использованием lambdas, это будет накладные расходы при отладке кода в случае возникновения проблемы.

Ответ 6

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

1. Синтаксис

Анонимный класс:

package com.onlyfullstack;
public class LambdaVsAnonymousClass {

 public static void main(String[] args) {
  Runnable runnable = new  Runnable() {
   @Override
   public void run() {
    System.out.println("Anonymous class");
   }
  };

  Thread thread = new Thread(runnable);
  thread.start();
 }
}

Lambda:

package com.onlyfullstack;
public class LambdaVsAnonymousClass {

 public static void main(String[] args) {
  Runnable runnable = () -> System.out.println("Lambda Expression");

  Thread thread = new Thread(runnable);
  thread.start();
 }
}

2. Реализация

Анонимный класс может быть использован для реализации любого интерфейса с любым количеством абстрактных методов. Лямбда-выражение будет работать только с типами SAM (Single Abstract Method). Это интерфейс только с одним абстрактным методом, который также называется функциональным интерфейсом. Он потерпит неудачу, как только ваш интерфейс будет содержать более 1 абстрактного метода.

3. Компиляция

Анонимный класс: Java создает два файла класса для Java файла LambdaVsAnonymousClass как LambdaVsAnonymousClass.class - содержит основную программу LambdaVsAnonymousClass $ 1.class - содержит анонимный класс enter image description here

Лямбда-выражение: С помощью лямбда-выражения компилятор создаст только 1 файл класса, как показано ниже. Lambda Expression

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

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

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

Лямбда-выражения Вместо генерации прямого байт-кода для лямбды (как предложенный подход к синтаксическому сахарному анонимному классу) компилятор объявляет рецепт (с помощью инструкций invokeDynamic) и делегирует реальный подход к построению во время выполнения.

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

Для получения дополнительной информации, пожалуйста, обратитесь к ссылкам ниже:

https://onlyfullstack.blogspot.com/2019/02/lambda-vs-anonymous-class-in-java-8.html

https://onlyfullstack.blogspot.com/2019/02/how-lambda-internally-works-in-java-8.html

Ответ 7

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

Ответ 8

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