29 Jan 2015 Java 8 – on the path to improving developer sanity
Rewire your brain. Do it now. That’s what Oracle wants you to do with the introduction of the Java 8 SE. Unnecessarily dramatic statements aside, the “JCP” have approved a number of new language features that bring functional programming to Java – and which Oracle are promoting so heavily, they may as well be walking around with “declarative programming is great” inked on their collective foreheads.
To be clear, this doesn’t even come close to transforming Java 8 into a pure functional language as some have misattributed it and then remarked when that construct has fallen down. Java is a multi-paradigm language with its origins obviously rooted in the imperative and object-oriented landscape. However, new language features have widened up the scope to which functional programming concepts can be applied so it’s worth considering those implications.
You may also be wondering where this functional madness will end, will Java 9 deprecate variables in favour of higher-order functions? You might attempt to answer these questions by simply researching future JEPs, but a much more interesting and pretentious thought exercise would be to infer the objectives of language authors by analysing new language features in excruciating detail. Consider then, why streams may have made their way into Java 8, and ready yourself for some outlandish claims.
Streams offer huge benefits and are generally underutilised in high-level programming. Most notably, streams offer a way of processing I/O in chunks without having to buffer the full dataset into memory ahead of time. This prevents an ENOMEM crash when the size of your database query multiples overnight, which means streaming ticks that ever-present, nearly unobtainable “scalable” checkbox that you all foam over like ravenous dogs fixated on a bone suspended inches above your gnashing jaws.
I/O performance doesn’t appear to be the driving motivation behind introducing the Java 8 streams API, though. Sure, they can do that, but Java always could. Have you heard of BufferedReader? What do you think ResultSet is doing? In fact, Java 8 streams are touted as the chemotherapy to the malignancy of uncomfortable collection iteration, which has a habit of spreading its hideous control mechanisms throughout your otherwise elegant codebase. Yes, iterators are competent enough, but don’t you want to write beautiful code?
List<String> animals = Arrays.asList("porcupines", "crocodiles", "pandas", "flamingos", "politicians"); List<String> filteredAnimals = new ArrayList<>(); for (String animal : animals) { if (animal.startsWith("p")) { filteredAnimals.add(animal.toUpperCase()); } } Collections.sort(filteredAnimals); for (String animal : filteredAnimals) { System.out.println(animal); }
This laborious collection iteration example will generate a sorted list of animals beginning with ‘p’
List animals = Arrays.asList("porcupines", "crocodiles", "pandas", "flamingos", "politicians"); animals .stream() .filter(animal -> animal.startsWith("p")) .map(String::toUpperCase) .sorted() .forEach(System.out::println);
The equivalent stream example offers vastly heightened developer satisfaction
Of course, the previous example highlights what you should already be well aware of – that eliminating metastasized multi-nested collection loops with stream chemotherapy requires a vastly different technique than the one required to wield the scalpel of iterators. If you’re not already acquainted with functional programming, you’ll need to learn to master those somewhat unnerving declarative expressions which look friendly enough but behave a little unpredictably, not unlike that estranged Uncle of yours who showed up drunk and uninvited to your birthday party that one time in 7th grade…
“If I could just write map, I would’ve been done by now. But I can’t. I have to create a new iterator and do a while loop and test for the next thing…”
– Aaron Patterson on the depression of working with Java
It should come as no surprise then, that most of Java’s documentation describe streams in the context of manipulating in-memory collections. Contrast this with Node.js’ Streams API where there’s a wealth of examples demonstrating their usefulness in performing I/O operations. In reality, the two are not dissimilar, Java offers up many convenience methods as part of the standard library that would need to be obtained through Node packages. The reason behind this disparity appears to be one of fundamentals between the two technologies, node.js’ priority being performant, scalable I/O whereas Java is attempting to cultivate a stable, “developer-friendly” platform.
Files.newBufferedReader(Paths.get("file.txt")) .lines() .map(w -> w.split(",")) .flatMap(Arrays::stream) .filter(s -> s.contains("c")) .map(animal -> animal.replace("c", "k")) .forEach(System.out::print);
Consuming and manipulating an I/O stream with Java 8
fs.createReadStream("./file.txt") .pipe(es.split(",")) .pipe(filter(function (animal) { return animal.indexOf("c") > -1 })) .pipe(es.replace("c", "k")) .pipe(process.stdout);
Node.js’ does it in much the same way (using event-stream and stream-filter)
To be fair, parallelisation does appear to be a secondary motivating factor in the original streams proposal, but even this is placed in the context of making it easy for developers. Then there’s the much-hyped lambdas which add limited closure support to Java, ever heightening developer thirst for functional programming. The motivation behind lambdas reads very much like a young child demanding candy because his fellow classmates have some, but you shouldn’t frown upon this because truth be told, candy is fantastic. Lambdas are genuinely useful in a variety of different ways, the least of which is probably the code reduction gain when writing the occasionally-useful, anonymous inner class. You probably haven’t been this excited for programming efficiency since Sun introduced generics in Java 5.
The ease of composability that both streams and lambdas offer is a breath of fresh air in a world governed by stifling, over-regulated interfaces – a sickening construct reminiscent of an overbearing bureaucracy. In practice, Java interfaces are highly desirable, but this is only because they provide a means of escape from the strictly-typed, prison-like embrace of the Java compiler. However, these new language features may be the blood transfusion Java needs to bring some hipper, skinny-jeans-wearing developers to a language otherwise dominated by mundane but probably necessary enterprise applications.

This guy probably codes in Ruby. (photograph: Richard Pendavingh)
It seems perversely obvious then – something which should’ve been evident a half-dozen paragraphs ago – that the goals of the evolving Java language are to improve the downtrodden lives of those who devote their time developing applications within it. It’s doubtful that “functional programming” was thrown out as a high-level objective, it’s more likely a mere side-effect of finding constructs that address the main weaknesses in the language. It makes sense, software problems are unique and one paradigm may be better suited for a particular class of problem over another.
The convergence of languages is an interesting one. Take Java and JavaScript which have historically been similar in much the same way a car is similar to carpet. Yet, overlooking some implementation differences, the Java 8 features described previously are reminiscent of JavaScript’s closures and Node.js’ Stream API. Conversely, the ES6 specification introduces the Java concepts of classes and block scoping. Looking more widely, there’s also the influx of JavaScript supersets such as TypeScript and AtScript that bolt strong-typing on top of the classically dynamic language.
One has to wonder if language choice will soon be based primarily on personal syntactic preference and the availability of libraries over language features and programming paradigms. The trend certainly seems to be heading in that direction. Nevertheless, you can rest easy knowing that this year’s advances will probably have you writing software to grow your application. Which probably isn’t as outlandish as you think.
No Comments