Статьи

Игра с Java 8 лямбд в JDT

Я немного поигрался с языком, пока возился с поддержкой Java 8, разрабатываемой  проектом Eclipse  Java development tools (JDT).

Я признаю, что я немного не в восторге от  лямбд в Java 8 . Это, конечно, исходит от  Старого Чувака, Который знает Smalltalk  (и LISP / Scheme).

Чувак старого кудряща, который знает болтун

 Чувак старого 

кудряща,
который знает болтун

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

Начиная примерно так:

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 вы могли бы сделать что-то вроде этого, чтобы найти сотрудников с опытом работы более пяти лет:

List longTerm = new ArrayList();
for(Employee employee : employees) 
	if (employee.years > 5) longTerm.add(employee);

Используя лямбды, вы можете сделать что-то вроде этого:

OrderedCollection longTerm = 
	employees.select(employee -> employee.years > 5);

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

OrderedCollection longTerm = employees.select(new SelectBlock() {
	@Override
	public boolean value(Employee employee) {
		return employee.years > 5;
	}
});

Анонимные занятия заставляют детей плакать.

Конечно, дети не особенно рады реализации  select() :

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 незначительно с точки зрения читабельности, но его гораздо легче понять, чем пример анонимного класса. С точки зрения производительности, я ожидаю, что использование lambdas или анонимных классов в этом контексте будет на порядок хуже, чем просто использование  for-loop.

Одна из самых интересных вещей, которые мы делаем в Smalltalk, — это создание собственных управляющих структур. Вместо создания совершенно новой коллекции вы можете создать собственные итераторы, например:

payroll.longTermEmployeesDo(employee -> payroll.giveEmployeeARaise(employee));

Или что-то вроде того. Я не уверен, если это делает это лучше или нет.

Простые коллекции могут быть не лучшим использованием лямбд. Лямбды не так полезны (или, как я считаю, эффективнее), как  блоки в Smalltalk . Мне нужно потратить немного больше времени на изучение примеров, когда использование анонимных классов более естественно в Java ( Runnables и слушатели кажутся очевидным местом для начала).

К сожалению, я думаю, что попытка реализовать подобные Smalltalk коллекции с использованием лямбд в Java 8 также заставит детей плакать.

Как прощальный выстрел … попробуйте обернуть свой мозг вокруг этого:

double average = (double)employees.inject(0, 
	(sum, employee) -> sum + employee.years) / employees.size();

Полностью читабельный. Полностью.