Playing with Java 8 Lambdas in the JDT

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).

Old Curmudgeon Dude Who Knows Smalltalk

Old Curmudgeon Dude Who Knows Smalltalk

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 (Runnables 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).

This entry was posted in Java and tagged , , , . Bookmark the permalink.

3 Responses to Playing with Java 8 Lambdas in the JDT

  1. Hi,

    I would argue a little bit about the performance of the lambdas.

    First of all, in most cases, although lambdas are semantically equivalent of anonymous classes, as they use define only a single method (by design), they can be replaced by a corresponding method call instead of instantiating a new class. That can be much cheaper.

    Second, if using lambdas for more complex cases (not a simple filtering), the possibility that they can be implemented as lazy collections (where everything is executed only when needed, not before), serious performance and/or memory gains can be achieved by simply not instantiating unnecessary objects and additional collections.

    We had a case in the EMF-IncQuery project where we replaced the creation of a copy of a list with the iteration and processing (using an anonymous class), and in case of large models we gained 300MB of RAM (from a total of 3,5 GB), and execution also become much speedier.

    In other words, I believe, lambdas are a really great addition, especially, if they are used in environments that know about them, thus allowing additional performance gains. The enhanced readability is an added bonus to me.

    Zoltán

    • waynebeaton says:

      I should have more correctly labeled my observations and initial impressions that require more research. Apparently, lambdas are not semantically equivalent to anonymous classes. For one, I have read that this is tied to the containing method scope (as opposed to the anonymous class instance scope). Also, there are, apparently, some compiler differences that permit optimizations that are not possible with anonymous classes. Very encouraging.

  2. I did find the ‘inject’ method pretty readable, but maybe because my experience with FP, they should have call it foldLeft though

Leave a comment