Рубрики
Без рубрики

Эффективная Java! Предпочитайте лямбды анонимным классам

Погружение в главу 42 Эффективной Java. Помечено как java, эффективный, аннотация, архитектура.

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

До появления лямбд в качестве типов функций/| использовались интерфейсы, а иногда и абстрактные классы с одним методом . Реализации этих экземпляров будут созданы с помощью анонимных внутренних классов и позволят использовать форму функционального программирования в вашем Java-коде. Давайте рассмотрим пример:

Collections.sort(words, new Comparator () {
  public int compare(String s1, String s2) {
    return Integer.compare(s1.length(), s2.length());
  }
});

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

Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length());

Даже с этим самым незначительным изменением для использования лямбд мы избавляемся практически от всего шаблонного кода. Мы видим, что параметры lamba не объявляют тип. Это связано с тем, что лямбды могут использовать вывод типа (например, variety ключевое слово в последних версиях Java), которые также позволяют нам пропустить этот шаблон. Это не значит, что мы не можем указать тип, и в редких случаях компилятор не сможет определить тип, только в этих случаях, когда компилятор требует, мы должны определить тип. Есть еще более короткие способы, которыми мы можем написать вышеизложенное, такие как использование методов построения компаратора вместе со ссылкой на метод:

Collections.sort(words, comparingInt(String::length));

или еще короче с использованием метода List.sort (пример метода по умолчанию)

words.sort(commparingInt(String::length));

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

В предыдущей главе мы обсуждали Operation enum, который выглядел примерно так:

public enum Operation {
  PLUS { public double apply(double x, double y) { return x + y;}},
  MINUS { public double apply(double x, double y) { return x - y; }},
  TIMES { public double apply(double x, double y) { return x * y; }},
  DIVIDE { public double apply(double x, double y) {  return x / y; }};

 public abstract double apply(double x, double y);
}

мы можем упростить этот код, используя лямбды:

public enum Operation {
  PLUS((x,y) -> x + y),
  MINUS((x,y) -> x - y),
  TIMES((x,y) -> x * y),,
  DIVIDE((x,y) -> x / y),

  private final DoubleBinaryOperator operator;

  Operation(DoubleBinaryOperator operator) {
    this.operator = operator;
  }

  public double apply(double x, double y) {
    return operator.applyAsDouble(x, y);
  }
}

В приведенном выше примере используется класс DoubleBinaryOperator , который является лишь одним из многих интерфейсов в пакете java.util.function , который полон множества различных полезных интерфейсов. Этот, в частности, принимает два параметра double и возвращает другой double . Вы можете создать свой собственный интерфейс, подобный этому, просто создав интерфейс с помощью одного метода, а затем аннотируя класс с помощью @FunctionalInterface . Аннотация, похожая на аннотацию @Override , не определяет поведение, а просто указывает компилятору, что ожидается, что этот класс будет иметь только один метод и не сможет скомпилироваться, если вы не соответствуете ожиданиям функционального интерфейса.

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

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

Оригинал: “https://dev.to/kylec32/effective-java-perfer-lambdas-to-anonymous-classes-5co6”