Эта новая глава подводит нас к новому разделу, посвященному некоторым новым функциям 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”