Java 10 – Local Variable Type Inference

In a previous post I listed the features added to Java 10. Naturally in a six-month update, the list isn’t long and most of them are updates to the runtime (such as very welcome garbage collector updates or internal changes).

But the number 1 headline grabber is the addition of type inference for local variables, and it’s a biggie. Let’s take it for spin.

What is type inference?

You’re all familiar with the following ritual:

 Customer customer = new Customer("Alan");

Which, if you think about it, is a bit absurd. We have to tell the compiler twice what type of object we’re creating. There is a reasoning behind this – technically the left hand side is telling the compiler what type we want the reference to be stored as, whilst the right hand side is the concrete object we’re creating. Sometimes, the difference is important and relevant – when programming to interfaces.

Example:

AbstractCustomer customer = new CreditCustomer("Alan");

Here want to instantiate a specific type of customer, but for the rest of the code, we only want to call the methods that are common to all customers. Polymorphism, blah blah blah. We’re not interested in that today, I just wanted to point out there is a reason for the left-hand-side-right-hand-side apparent duplication.

Here’s the thing – for the most part the two sides of the equation are duplicated. I want a customer and it needs to be of type customer.

Don’t Repeat Yourself is a bad thing and it’s almost like traditional Java wants us to repeat ourselves!

Anyway, stop waffling and cut to the chase. From Java 10 onwards, we can now let the compiler guess – or infer the type that we want…

 var customer = new Customer("Alan");

“var” is one of those rare things in Java, a brand new keyword! Java will now guess (it’s not hard is it?) that the type we want is Customer.

That’s it.

For the rest of the post I’ll describe a more realistic use of var. I’m picking an example from Spark, but don’t worry if you haven’t used Spark before, the example is actually generic.

A Real World Example

As usual with these toy examples, things don’t seem very groundbreaking but I believe this feature will have a major and positive impact on code productivity. Consider this monster from my Spark Training Course:

result = totals.mapToPair(tuple -> new Tuple2<Long, String> (tuple._2, tuple._1 ));

Now, I should know what the return type from this method call is. Erm, well, I should but it’s a bit of a headache. I know that the return class is some kind of “RDD”, I think a JavaRDD. And I can guess from the <Long, String> that the resulting return type will also have the same generic. So, I nervously type into the IDE:

JavaRDD<Long, String> result = totals.mapToPair(tuple -> new Tuple2<Long, String> (tuple._2, tuple._1 ));

Ouch. No! I now have a compile error…the type on the Left Hand Side is wrong. So now we reach a ludicrous situation: the compiler knows what the type should be, and I don’t. And the compiler won’t let me proceed until I guess correctly. (Ok, what I mean is – until I work out the right type).

Often on the Spark course I advise the viewer to simply leave off the return type and then use Quick Fix for the IDE to add in what it thinks is the right type!

Using the “Create Local Variable” Quick Fix should add in the left-hand-side declaration automatically.

I only advise using Quick Fixes if you know what you’re doing – in this case I’m basically asking Eclipse to do a type inference for me. But it’s very hit and miss – in this case, it gets it wrong. Or sort of half right:

For some reason (I care not why) the generics on the left hand side haven’t been inferred so the compiler is still moaning. A second “quick” fix will rectify this…

And – hooray, we finally have the right answer – it seems I had forgotten that the type was actually “JavaPairRDD”:

 JavaPairRDD<Long, String> result = totals.mapToPair(tuple -> new Tuple2<Long, String> (tuple._2, tuple._1 ));

But what a performance! And obviously the compiler knew the right answer all along. It was just teasing us.

So, to the point – when working in real coding situations like this, it can be easy to be unsure of the correct type you need for the declaration – and actually knowing the right type isn’t particularly illuminating. So, in Java 10 I could have avoided all that mess and jumped straight to:

 var result = totals.mapToPair(tuple -> new Tuple2<Long, String> (tuple._2, tuple._1 ));

Much cleaner and I hope in the long run, simpler. Note that none of this destroys strong typing – the type of result is still the same as it was, and we can only call the methods defined in the JavaPairRDD class, exactly as before.

I hope these kind of modern features are going to come thick and fast to future Java versions and that it will prove a compelling reason to upgrade – only time will tell…

[A footnote that after a long discussion Java decided not to implement a var/val keyword pair as in Scala. val would define an immutable value – whilst valuable it was decided this would over-complicate type inference, and it is arguably not all that useful on local variables anyway. That’s a bit disappointing but it’s true that immutability is orthogonal to type inference. I hope that a future version of Java will introduce some strong language level support for immutability.]

Trying Java 10 in Eclipse

If you’re keen to try Java 10 (of course you are!) then you can download the JDK from Oracle at the usual place.

I’m still with Eclipse (for the time being at least), and to use Java 10 (at the time of writing), you need to be on the latest version (currently Oxygen.3 aka 4.7.3) and you need to install (via the Marketplace) a Java 10 plugin.

Java 10 on the Marketplace

After installing the plugin, restart Eclipse and then define a JDK (using the usual tortuous Window -> Preferences -> Java -> Installed JREs and navigate to the folder you downloaded the JDK to).If you haven’t installed the plugin, this will fail because eclipse won’t recognise the new structure and layout of the JDK.

Now you can create a new project – I haven’t changed my default compiler compliance level so I’m getting a promising looking message saying the compliance level is going to be changed for this project…

New Project Window – looks like the compliance level is going to be set properly!

And that’s it. You can now create a class and start using the new features – the next blog post will explore what I think is the best of them, Local Variable Type Inference.

[edit1: I’m far too Eclipse-centric, I do need to address this soon. I can’t see any sign of Java 10 support in NetBeans but JetBrains/IntelliJ as usual are well ahead of the curve, they announced support for Java 10 as far back as last November. ]

[edit2: JetBrains are running a live Java 10 Webinar hosted by Trisha Gee on Thursday, Apr 5 2018, 4:00 PM – 5:00 PM CEST, check it out if you can.]

Java 10 is here…already!

Wow – that was quick. After years of interminable delays to Java 9, all of a sudden the new strict release cycle has kicked in and the first result of that, Java 10 was released on March 20 2018.

In brief, there will be a new release of Java every 6 months from now on and every three years there will be a “long term support” release. Java 11 (due late 2018) is planned to be the first LTS. (Thanks to David Morgan in the comments for spotting my error in early versions of this post!)

Obviously many projects/organizations will insist on only using the LTS releases, so the reality for many Java developers is that adopting Java 11 will probably be long term stretch goal. (By my reckoning, if they keep their promise, Java 17 will be the next LTS after that – it will interesting psychological challenge for the likes of banks to upgrade from 11 to 17 in one jump!).

For anyone not tied to LTS releases, we’re going to get a new set of toys to play with every six months!

Here’s the full set of JEPs (JDK Enhancement Proposals) you can use right now in Java 10. Most of them are under the hood enhancements, cleanups and non-coding related changes. But the headline for Java programmers is the first of them, JEP286 – which I’ll write about in my next blog post. It’s a stunning improvement to Java.

286: Local-Variable Type Inference
296: Consolidate the JDK Forest into a Single Repository
304: Garbage-Collector Interface
307: Parallel Full GC for G1
310: Application Class-Data Sharing
312: Thread-Local Handshakes
313: Remove the Native-Header Generation Tool (javah)
314: Additional Unicode Language-Tag Extensions
316: Heap Allocation on Alternative Memory Devices
317: Experimental Java-Based JIT Compiler
319: Root Certificates
322: Time-Based Release Versioning

Hello, is this thing on?

A year’s gap from blogging – bad Richard.

Blogging sort of tailed off, partly as a result of the ancient and depressing blog platform I was using (every post needed the editing of raw 1990’s style html – <hr> tags anyone?) but also due to a lot of activity and general busy-ness at VirtualPairProgrammers.

In the last year I’ve released courses on:

Plus as a substitute for blogging, I’ve been a regular guest on the All things Java Podcast which was fun but apparantly no-one listens to it. [Edit: the podcasts will continue and I hope I’ll still be a guest on them, but I want to remind myself that blogging is just as if not more important than podcasts]. So it’s back to blogging and more new courses are in the pipeline.