<< PreviousNovember 2013Next >>

Thursday 28 November, 2013
#The Forest Road Reader, No 113

We live now, of course, in a previously unimaginably crazy futureworld where C++ got lambdas before Java. Some time next year (and, of course, subject to our corporate overlords and their various contractual relationships) those of us nurdling around in Javaland will be able to replace those clunky anonymous classes with sleek new Java lambdas. We'll go from this

  List<U> r = from(list).
                 where(new Predicate { public boolean test(T t) { ... } ).
                 select(new Function { public U apply(T t) { ... }).
                 toList();
to this
  List<U> r = from(list).
                 where(t -> ...).
                 select(u -> ...).
                 toList();
Much nicer!

In fact, if we dig a little deeper in Java 8, we can write this.

  List<U> r = list.stream().
                 filter(t -> ...).
                 map(u -> ...).
                 collect(Collectors.toList());
and I can chuck out my code completely. Remarkably this stuff is baked into the standard java.util package.

I say remarkably because the java.util package, while undeniably java, hasn't laboured very much on the util. The Queue and Deque interfaces and their implementations, for instance, didn't arrive until Java 6. The Objects utility methods didn't arrive until Java 7. Many of the iterfaces and classes in util give the impression of usefulness by being maximalist - they have lots and lots of methods. Lots of methods == more utility, right? Well, no.

Consider the List iterface, which has 23 methods. It includes a full set of methods to get, set, insert, and remove items from the list at a specific index. You almost certainly only what to perform those operations on a List that provides O(1) random access. You almost certainly don't want to be doing that on a linked list for instance. And not only will Java let you, its library interfaces mandate that a list *must* support

There's the rather curious List.retainAll(Collection<T> coll) method, which removes everyting from the List which isn't in the provided collection. I accept there are times when you want to this, but it's not so common you need to provide as a method on all List implementations. Surely the more common case, given that you've gathered up the things you need into a second collection, is simply to discard the first collection? I don't see how it can be implemented remotely efficiently either. (retainAll is not, as far as I can tell, used in the Java 7 source.)

A rather striking omission from the List interface is sort. That's a really, really common operation, and one that could reasonably be provided as a member method. ArrayList.sort, for instance, could sort its backing array in place, while LinkedList.sort would have to go rather more round the houses. Instead we have the Collections.sort static method. It's "generic" in the sense that it works with all List implementations and treats them all in the same way. And that way is to copy the list's contents into an array, sort the array, and then write the array's contents back into the list. (Collections.sort is called 16 times in the Java 7 source.)

As an additional oddity, since Java 1.4 java.util has provided the RandomAccess marker interface to indicate that Lists support fast random access. Presumably it was introduced because somebody somewhere reviewed List and clapped a hand to their forehead while yelling a loud "DOH". Backward compatibility ruled out changing List and so RandomAccess was introduced "to allow generic algorithms to alter their behaviour to provide good performance when applied to either random or sequential access lists". If you poke around in the handful of generic algorithm provided in Collections, shuffle for instance, rotate, or swap, they do all switch on RandomAccess and act accordingly. But not sort. Even in Java 8, the single most common List operation copies the list, sorts the copy, then does a linear traverse to overwrite the original.

In marked contrast, the new Stream stuff looks terrific (and I'm not just saying that because it looks virtually identical to what I wrote) and I can hope it introduces a step-change in how we use Java collections. I'd ramble on some more, but I've been up since half four this morning. Tomorrow, maybe.

Scott [e] said Wow... it's GROOVY!

:) [added 2nd Dec 2013]

It is pretty Groovy, but there's more in the streams, particularly in its support for parallelism. I'm up early again tomorrow so maybe I'll bang on about that then :) [added 2nd Dec 2013]

[Add a comment]