it-swarm.com.ru

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

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

Я немного исследовал эту тему и нашел несколько интересных примеров того, как лямбда-выражения будут систематически заменять эти классы, например, метод сортировки 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 вместо классов Anonymous, поскольку Lambdas можно использовать только с интерфейсами с одним методом, является ли эта новая функция только ярлыком, используемым только в нескольких случаях, или она действительно полезна?

89
Amin Abu-Taleb

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

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

ОБНОВЛЕНИЕ

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

86
Stuart Marks

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

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

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

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

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

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

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

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

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

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

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

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

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

29
Dmitriy Kuzkin

Есть следующие отличия: 

1) Синтаксис

Лямбда-выражения выглядят аккуратно по сравнению с Anonymous Inner Class (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 и this при использовании внутри анонимного внутреннего класса и лямбда-выражения. В случае анонимного внутреннего класса это ключевое слово относится к локальной области видимости, а супер ключевое слово относится к суперклассу анонимного класса. В то время как в случае лямбда-выражения это ключевое слово относится к объекту вмещающего типа, а 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) Результат

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

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

10
atom217

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

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

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

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

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

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. Реализация

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

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

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

Lambda Expression: Компилятор лямбда-выражений создаст только 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

0
Saurabh Oza

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

0
spidy