I’ve been playing with the language a bit while tinkering with the Java 8 support under development by the Eclipse Java development tools (JDT) project.
I’ll admit that I’m a little underwhelmed by lambdas in Java 8. This, of course, comes from an Old Dude Who Knows Smalltalk (and LISP/Scheme).
Like any good Smalltalk curmudgeon, when I set about learning how to use lambdas, I naturally decided to implement the known and loved collections.
Starting from something like this:
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));
In classic Java, you’d do something like this to find employees with more than five years of experience:
List longTerm = new ArrayList(); for(Employee employee : employees) if (employee.years > 5) longTerm.add(employee);
Using lambdas, you might do something like this:
OrderedCollection longTerm = employees.select(employee -> employee.years > 5);
It’s a little tighter than classic Java, and I personally find it very readable and understandable; readers with different experiences may have a different option. I believe that it is way better than the equivalent implementation with an anonymous class:
OrderedCollection longTerm = employees.select(new SelectBlock() { @Override public boolean value(Employee employee) { return employee.years > 5; } });
Anonymous classes make babies cry.
Of course, babies aren’t particularly happy about the implementation of select()
either:
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; } ... }
Lambdas are syntactic sugar for anonymous classes, and do arguably make some code easier to read. For my rather simplistic example, the benefit over the direct use of a for
-loop is marginal from a readability point-of-view, but it’s far easier to understand than the anonymous class example. From a performance point-of-view, I expect that using lambdas or anonymous classes in this context would be something like an order of magnitude worse than just using a for
-loop.
One of the cooler things that we do in Smalltalk is create our own control structures. Instead of creating a whole new collection, you could create custom iterators, e.g.:
payroll.longTermEmployeesDo(employee -> payroll.giveEmployeeARaise(employee));
Or something like that. I’m not sure if this makes it better or not.
Simple collections might not be the best use of lambdas. Lambdas are not quite as useful (or, I believe, as efficient) as blocks in Smalltalk. I’ll need to spend a little more time tinkering with examples where the use of anonymous classes is more natural in Java (Runnable
s and listeners seem like an obvious place to start).
Unfortunately, I think that trying to implement Smalltalk-like collections using lambdas in Java 8 will also make babies cry.
As a parting shot… try to wrap your brain around this:
double average = (double)employees.inject(0, (sum, employee) -> sum + employee.years) / employees.size();
Totally readable. Totally.
Modified on Feb 18/2014. My initial observations led me to believe that lambdas are syntactic sugar for anonymous classes. I’ve since learned that this is not the case. Further, there are some optimizations that I need to better understand. I’ve struck out the incorrect statements (but have otherwise left it for posterity).