Есть ли у лямбда-выражений какое-либо применение, кроме сохранения строк кода?
Есть ли какие-либо специальные функции, предоставляемые лямбдами, которые решают проблемы, которые было нелегко решить? Типичное использование, которое я видел, заключается в том, что вместо написания этого:
Comparator<Developer> byName = new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getName().compareTo(o2.getName());
}
};
Мы можем использовать лямбда-выражение, чтобы сократить код:
Comparator<Developer> byName =
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName());
(o1, o2) -> o1.getName().compareTo(o2.getName())
Comparator.comparing(Developer::getName)
Ответы:
Лямбда-выражения не меняют набор проблем, которые вы можете решить с помощью Java в целом, но определенно упрощают решение определенных проблем, по той же причине, по которой мы больше не программируем на языке ассемблера. Удаление избыточных задач из работы программиста облегчает жизнь и позволяет делать то, чего вы даже не трогали бы в противном случае, просто за тот объем кода, который вам пришлось бы создать (вручную).
Но лямбда-выражения - это не просто сохранение строк кода. Лямбда-выражения позволяют определять функции , для которых раньше вы могли использовать анонимные внутренние классы в качестве обходного пути, поэтому вы можете заменить анонимные внутренние классы в этих случаях, но не в целом.
В частности, лямбда-выражения определяются независимо от функционального интерфейса, в который они будут преобразованы, поэтому нет унаследованных членов, к которым они могли бы получить доступ, кроме того, они не могут получить доступ к экземпляру типа, реализующего функциональный интерфейс. В лямбда-выражении
this
иsuper
имеют то же значение, что и в окружающем контексте, см. Также этот ответ . Кроме того, вы не можете создавать новые локальные переменные, скрывающие локальные переменные окружающего контекста. Для предполагаемой задачи определения функции это удаляет множество источников ошибок, но также подразумевает, что для других случаев использования могут существовать анонимные внутренние классы, которые нельзя преобразовать в лямбда-выражение, даже если реализуется функциональный интерфейс.Кроме того, конструкция
new Type() { … }
гарантирует создание нового отдельного экземпляра (какnew
всегда). Экземпляры анонимного внутреннего класса всегда сохраняют ссылку на свой внешний экземпляр, если они созданы внеstatic
контекста. Напротив, лямбда-выражения захватывают ссылку толькоthis
тогда, когда это необходимо, то есть если они обращаютсяthis
или не являютсяstatic
членами. И они создают экземпляры намеренно неуказанной идентичности, что позволяет реализации решать во время выполнения, следует ли повторно использовать существующие экземпляры (см. Также « Создает ли лямбда-выражение объект в куче каждый раз при выполнении? »).Эти различия относятся к вашему примеру. Конструкция вашего анонимного внутреннего класса всегда будет создавать новый экземпляр, а также может захватывать ссылку на внешний экземпляр, тогда как ваше
(Developer o1, Developer o2) -> o1.getName().compareTo(o2.getName())
лямбда-выражение без захвата, которое в типичных реализациях будет оцениваться как одноэлементное. Кроме того, он не производит.class
файл на вашем жестком диске.Учитывая различия, касающиеся как семантики, так и производительности, лямбда-выражения могут изменить способ решения программистами определенных проблем в будущем, конечно, также из-за новых API, охватывающих идеи функционального программирования с использованием новых функций языка. См. Также лямбда-выражение Java 8 и первоклассные значения .
источник
Языки программирования не предназначены для исполнения машинами.
Они предназначены для размышления программистами .
Языки - это диалог с компилятором, который превращает наши мысли в нечто, что может выполнить машина. Одна из главных жалоб на Java со стороны людей, которые пришли к ней с других языков (или оставили ее для других языков), заключалась в том, что она заставляет программисту определенную ментальную модель (то есть все является классом).
Я не собираюсь взвешивать, хорошо это или плохо: все дело в компромиссах. Но лямбды Java 8 позволяют программистам мыслить в терминах функций. , чего раньше в Java делать нельзя.
Это то же самое, что и процедурный программист, который учится думать категориями классов, когда приходит к Java: вы видите, как они постепенно переходят от классов, которые являются прославленными структурами и имеют `` вспомогательные '' классы с кучей статических методов, и переходят к чему-то, что больше напоминает рациональный объектно-ориентированный дизайн (mea culpa).
Если вы просто думаете о них как о более коротком способе выражения анонимных внутренних классов, то вы, вероятно, не найдете их очень впечатляющими в той же мере, в какой процедурный программист выше, вероятно, не считал классы большим улучшением.
источник
Сохранение строк кода можно рассматривать как новую функцию, если она позволяет вам писать значительную часть логики более коротким и ясным образом, что требует меньше времени для прочтения и понимания другими.
Без лямбда-выражений (и / или ссылок на методы)
Stream
конвейеры были бы гораздо менее читабельны.Подумайте, например, как
Stream
выглядел бы следующий конвейер, если бы вы заменили каждое лямбда-выражение экземпляром анонимного класса.Это было бы:
Это намного сложнее написать, чем версию с лямбда-выражениями, и она гораздо более подвержена ошибкам. Это также труднее понять.
И это относительно короткий трубопровод.
Чтобы сделать это читаемым без лямбда-выражений и ссылок на методы, вам пришлось бы определить переменные, которые содержат различные экземпляры функционального интерфейса, используемые здесь, что разделило бы логику конвейера, что затруднило бы понимание.
источник
Comparator
for,sorted
поскольку оно все равно сравнивается в естественном порядке. Может быть, изменить его на сравнение длины строк или подобное, чтобы сделать пример еще лучше?compareToIgnoreCase
чтобы он вел себя иначе, чемsorted()
.compareToIgnoreCase
по-прежнему является плохим примером, поскольку вы можете просто использовать существующийString.CASE_INSENSITIVE_ORDER
компаратор. Предложение @tobias_k о сравнении по длине (или любому другому свойству, не имеющему встроенного компаратора) подходит лучше. Судя по примерам кода SO Q&A, лямбда-выражения вызвали множество ненужных реализаций компаратора…Внутренняя итерация
При повторении коллекций Java большинство разработчиков стремятся получить элемент, а затем обработать его. То есть выньте этот элемент и затем используйте его или повторно вставьте и т. Д. В версиях Java до 8 вы можете реализовать внутренний класс и сделать что-то вроде:
Теперь с Java 8 вы можете работать лучше и менее многословно:
или лучше
Поведение как аргумент
Угадайте следующий случай:
С интерфейсом Java 8 Predicate вы можете добиться большего:
Называя это так:
Источник: DZone - Почему нам нужны лямбда-выражения в Java
источник
numbers.forEach((Integer value) -> System.out.println(value));
лямбда-выражение состоит из двух частей: одна слева от символа стрелки (->), в которой перечислены его параметры, и правая, содержащая его тело . Компилятор автоматически определяет, что лямбда-выражение имеет ту же сигнатуру, что и единственный нереализованный метод интерфейса Consumer.Существует много преимуществ использования лямбда-выражений вместо внутреннего класса, как показано ниже:
Сделайте код более компактным и выразительным, не вводя дополнительную семантику синтаксиса языка. вы уже привели пример в своем вопросе.
Используя лямбды, вы можете программировать с операциями функционального стиля над потоками элементов, такими как преобразования map-reduce в коллекциях. см. документацию пакетов java.util.function и java.util.stream .
Компилятор не создает файла физических классов для лямбда-выражений. Таким образом, ваши доставленные приложения становятся меньше. Как память назначается лямбде?
Компилятор оптимизирует создание лямбда, если лямбда не обращается к переменным вне своей области видимости, что означает, что экземпляр лямбда создается JVM только один раз. для более подробной информации вы можете увидеть ответ @ Holger на вопрос Является ли кеширование ссылок на методы хорошей идеей в Java 8? ,
Lambdas может реализовывать интерфейсы с несколькими маркерами помимо функционального интерфейса, но анонимные внутренние классы не могут реализовывать больше интерфейсов, например:
источник
Лямбды - это просто синтаксический сахар для анонимных классов.
До лямбда-выражений для достижения того же можно было использовать анонимные классы. Каждое лямбда-выражение можно преобразовать в анонимный класс.
Если вы используете IntelliJ IDEA, он может выполнить преобразование за вас:
источник
Чтобы ответить на ваш вопрос, на самом деле лямбды не позволяют вам делать то, что вы не могли делать до java-8, а позволяют писать более сжатый код. Преимущества этого заключаются в том, что ваш код будет более ясным и гибким.
источник
Одна вещь, о которой я еще не упоминал, это то, что лямбда позволяет вам определять функциональность там, где она используется. .
Поэтому, если у вас есть какая-то простая функция выбора, вам не нужно помещать ее в отдельное место с кучей шаблонов, вы просто пишете лямбду, которая является краткой и актуальной для местных условий.
источник
Да, есть много преимуществ.
источник