Я немного поигрался с языком, пока возился с поддержкой Java 8, разрабатываемой проектом Eclipse Java development tools (JDT).
Я признаю, что я немного не в восторге от лямбд в Java 8 . Это, конечно, исходит от Старого Чувака, Который знает Smalltalk (и LISP / Scheme).
Как и любой хороший придурок Smalltalk, когда я начал изучать, как использовать лямбды, я, естественно, решил реализовать известные и любимые коллекции.
Начиная примерно так:
1
2
3
4
5
6
7
8
9
|
OrderedCollection employees = new OrderedCollection(); employees.add( new Employee( "Wayne" , 10 )); employees.add( new Employee( "Joel" , 9 )); employees.add( new Employee( "Jon" , 6 )); employees.add( new Employee( "Anthony" , 8 )); employees.add( new Employee( "Mary" , 2 )); employees.add( new Employee( "Sue" , 3 )); employees.add( new Employee( "Joanne" , 7 )); employees.add( new Employee( "Shridar" , 1 )); |
В классической Java вы могли бы сделать что-то подобное, чтобы найти сотрудников с более чем пятилетним опытом работы:
1
2
3
|
List longTerm = new ArrayList(); for (Employee employee : employees) if (employee.years > 5 ) longTerm.add(employee); |
Используя лямбды, вы можете сделать что-то вроде этого:
1
2
|
OrderedCollection longTerm = employees.select(employee -> employee.years > 5 ); |
Это немного труднее, чем классическая Java, и я лично нахожу это очень читабельным и понятным; у читателей с разным опытом может быть другой вариант. Я считаю, что это намного лучше, чем эквивалентная реализация с анонимным классом:
1
2
3
4
5
6
|
OrderedCollection longTerm = employees.select( new SelectBlock() { @Override public boolean value(Employee employee) { return employee.years > 5 ; } }); |
Анонимные занятия заставляют детей плакать.
Конечно, дети тоже не особенно рады реализации select()
:
01
02
03
04
05
06
07
08
09
10
11
|
public class OrderedCollection<T> extends ArrayList<T> { ... public OrderedCollection<T> select(SelectBlock<T> block) { OrderedCollection<T> select = new OrderedCollection<T>(); for (T value : this ) { if (block.value(value)) select.add(value); } return select; } ... } |
Лямбды являются синтаксическим сахаром для анонимных классов и, возможно, облегчают чтение некоторого кода. Для моего довольно упрощенного примера преимущество по сравнению с прямым использованием for
-loop незначительно с точки зрения читабельности, но его гораздо легче понять, чем пример анонимного класса. С точки зрения производительности, я ожидаю, что использование лямбда-выражений или анонимных классов в этом контексте будет на порядок хуже, чем использование for
-loop.
Одна из самых интересных вещей, которые мы делаем в Smalltalk, — это создание собственных управляющих структур. Вместо создания совершенно новой коллекции вы можете создать собственные итераторы, например:
1
|
payroll.longTermEmployeesDo(employee -> payroll.giveEmployeeARaise(employee)); |
Или что-то вроде того. Я не уверен, если это делает это лучше или нет.
Простые коллекции могут быть не лучшим использованием лямбд. Лямбды не так полезны (или, как я считаю, эффективнее), как блоки в Smalltalk . Мне нужно потратить немного больше времени на изучение примеров, когда использование анонимных классов более естественно в Java ( Runnable
s и слушатели кажутся очевидным местом для начала).
К сожалению, я думаю, что попытка реализовать подобные Smalltalk коллекции с использованием лямбд в Java 8 также заставит детей плакать.
Как прощальный выстрел … попробуйте обернуть свой мозг вокруг этого:
1
2
|
double average = ( double )employees.inject( 0 , (sum, employee) -> sum + employee.years) / employees.size(); |
Полностью читабельный. Полностью.
Изменено 18 февраля 2014 г. Мои первые наблюдения заставили меня поверить, что лямбды — это синтаксический сахар для анонимных классов. С тех пор я узнал, что это не так. Далее, есть некоторые оптимизации, которые мне нужно лучше понять. Я вычеркнул неправильные утверждения (но в остальном оставил это для потомков).