Ade Trenaman
Why Java 8 doesn’t rock my Scala

I was looking through this article on Java 8; we’re using Scala heavily at Gilt and I was toying with the heretical notion that Java 8 might create a compelling reason to go back to Java. Sacrilige! I am of course biased in this matter as I’ve really enjoyed the last two years of Scala coding at Gilt; however, my overall impression is that Java 8 is playing catch-up on Scala and not introducing anything radical. It’s a great boon for Java developers who want to be a bit more functional - that said, if you find yourself with those inclinations then you’re probably best off learning Scala ;)

Static methods on interfaces: Scala already lets you use traits with method implementations. So, nothing exciting to see here. Java 8’ ‘default methods’ introduce a new keyword ‘default’ with not much value. It’s not clear from the article to me what happens in the ‘diamond inheritance’; Scala has a graceful ‘stackable traits’ model so I assume that Java 8 will follow something similar.

Functional interfaces let you assign a lambda to an instance of a class with one method, as long as the lambda method signature can be coerced into the functional interface’s method. So you can do the following in Java 8:

   // Java 8

  Runnable r = () -> { System.out.println(“Running!”); }

This is nice; and it borrows from Scala’s ‘double-burger-arrow’ syntax. However, Scala does better type inferences:

  scala> val run = () => println(“running”)

… No need provide any explicit type information! Scala infers that run is a function that takes no parameters and returns Unit.

There’s a section on Lambda’s capturing / non-capturing lambdas in the article - the lambda ‘y’ below effectively ‘captures’ the value in ‘x’ at the time that it was created.

// Java

int x = 5;

return y -> x + y;

Capturing rules have implications that seem overly complicated: I don’t like the ambiguity around having to either mark a captured variable as final, or just making sure that the captured variable is not modified after the assignment assigned. I’m sure this is something that the compiler will barf on at compile time (which is OK); the solution will be to use final or remove the additional assignments. Seems crufty though; I’ve developed in Scala for the last two years and haven’t had to make this distinction. Check out the code below:

scala> var x = 5 // Note I’m making x a ‘var’, which I would never do!

x: Int = 5

scala> val doubleX = () => x * 2 // x will always be considered as ‘5’ for this lambda

doubleX: () => Int = <function0>

scala> doubleX()

res10: Int = 10

scala> x = 4

x: Int = 4

scala> doubleX()

res11: Int = 10

Java 8 brings in support for streams, which have already been in Scala for some time and boast a really elegant syntax. The Java 8 example given is

int sumOfWeights = blocks.stream().filter(b -> b.getColor() == RED)

                                  .mapToInt(b -> b.getWeight())

                                  .sum();

The above fragment is worth thinking about, in terms of it’s Scala alternative. Assume that I create a case class for Block, and then create a stream using the elegant Stream concatenation operator ‘#::’

case class Block(val color: String, val weight: Int)

val blocks = Block(“RED”, 2) #:: Block(“RED”, 4) #:: Block(“BLUE”, 23) #:: Stream.empty

Then, I end up with the smaller:

val sumOfWeights = blocks.filter(b => b.color == “RED”).map(b => b.weight).sum

… or even more expressive:

val sumOfWeights = blocks.filter( _.color == “RED” ).map( _.weight ).sum

Scala gives me a cleaner syntax - “Less is More”. More importantly, Scala’s type-inference makes crufty per-primitive methods like ‘mapToInt’ unnecessary  Scala is smart enough to infer the types. The Java 8 article also goes on to mention all of the new methods on Streams like ‘forEach’, ‘toArray’, etc: Scala’s awesome collection library already gives us this out of the box. Nicer still, Scala’s collection library adheres to the principal of least surprise: the same methods you expect on any of the other collections are there for you on Stream.

The additions to Java time are welcome; I can’t help but wonder though if the Joda Time boat has already sailed on that one. A tranche of new concurrency, futures and NIO methods are available; and then there’s a whole ton of new APIs like StringJoiner. I haven’t done a fully like-for-like analysis on those, but a quick scan shows me they’re generally things that Scala has already got sorted or that Scala will benefit from. It is nice to see Java get it’s own Optional<T> (at last!) although the article concedes that it’s ‘nothing at all’ like Scala’s Option.

In a nutshell, my resolve in Scala in strengthened - I might just go about playing with Java 8, but I’ll be sticking with Scala for my serious coding.

  1. raphaelalmeida reblogged this from ade-trenaman
  2. gilt-tech reblogged this from ade-trenaman
  3. ade-trenaman posted this