Local Variable Type Inference in Java 10

One handy feature that made the cut in JDK 10 release train is Local-Variable Type Inference (JEP-286). This language feature is part of project Amber, a successor to Project Coin πŸ™‚

With more frequent releases planned for the Java platform, we could expect to see 2 feature releases this year, so March release will be 18.3 and September LTS release will be 18.9. No kidding, Java 10 build#37 shows the release date πŸ˜‰

Screen Shot 2018-01-07 at 3.37.09 PM

We can expect to see small improvements every six months, so developers don’t have to wait for more than 2 years to catch up with the language. One such productivity-oriented language feature coming in Java 10 is Local-Variable Type Inference (LVTI).
Intellij IDEA 2017.3 has experimental support for this feature.

To enable this feature in your IntelliJ Java project, set the language level to “X – Experimental Features” under Project Settings.

Screen Shot 2018-01-07 at 3.53.33 PM

You can trigger this feature from their inspection too, which requires you to accept to their legal.

Screen Shot 2018-01-07 at 3.09.28 PM

Screen Shot 2018-01-07 at 3.09.55 PM

You can see it automatically detect code that can benefit from this syntactic sugar.

 

Screen Shot 2018-01-07 at 3.19.10 PM

It also supports reverting to old behavior, all the good stuff you are used to with IntelliJ IDEA.

Screen Shot 2018-01-07 at 4.10.20 PM

LTVI introduces a new context-sensitive keyword “var”, which technically is not a keyword, instead it is a restricted local variable type and cannot be used for type declarations. So, existing code which uses “var” in variable declarations or as a method name or package name will still be allowed, unlike class or interface name.

Here are some basic examples.


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
public class LocalVariableTypeInferenceTest {
private void processOrder(String order) {
System.out.println(order);
}
public static void main(String[] args) throws Exception {
// local variable use
var test = new LocalVariableTypeInferenceTest();
// infers HashSet<String> vs Set<String> orders = new HashSet<>();
var orders = new HashSet<String>();
// indexed for-loop use
for (var i = 0; i < 5; i++) {
orders.add(UUID.randomUUID().toString());
}
// for-each use
for (var order : orders) {
// process an order
test.processOrder(order);
}
// infers Stream<String>
var stream = orders.stream();
stream.forEachOrdered(test::processOrder);
// try-with-resources use
try (var in = Files.newInputStream(Paths.get("./src/LocalVariableTypeInferenceTest.java")); var reader = new BufferedReader(new InputStreamReader(in))) {
// print the imports
reader.lines().takeWhile(e -> !e.startsWith("public")).forEachOrdered(System.out::println);
} catch (IOException e) {
throw e;
}
}
}

Here is another example involving lambda.


import java.util.Comparator;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
public class RideTest {
interface RideProvider {
long getFareEstimate(String start_lat, String start_lng, String end_lat, String end_lng, String type);
}
public static void main(String[] args) {
var start_lat = "37.7749295";//San Francisco
var start_lng = "-122.41941550000001";//San Francisco
var end_lat = "37.3382082";//San Jose
var end_lng = "-121.88632860000001";//San Jose
var lyft = new RideProvider() {
@Override
public long getFareEstimate(String start_lat, String start_lng, String end_lat, String end_lng, String type) {
var estimated_cost_cents_max = 0;
switch (type) {
case "Line":
estimated_cost_cents_max = 3307;
break;
case "Lyft":
estimated_cost_cents_max = 7306;
break;
case "Plus":
estimated_cost_cents_max = 12451;
break;
case "Premier":
estimated_cost_cents_max = 17562;
break;
case "Lux":
estimated_cost_cents_max = 23624;
break;
case "Lux SUV":
estimated_cost_cents_max = 25879;
break;
}
return estimated_cost_cents_max;
}
};
var lyftFuture = CompletableFuture.supplyAsync(() -> lyft.getFareEstimate(start_lat, start_lng, end_lat, end_lng, "Lyft"));
var uber = new RideProvider() {
@Override
public long getFareEstimate(String start_lat, String start_lng, String end_lat, String end_lng, String type) {
var estimated_cost_cents_max = 0;
switch (type) {
case "POOL":
estimated_cost_cents_max = 7000;
break;
case "EXPRESS POOL":
estimated_cost_cents_max = 7000;
break;
case "uberX":
estimated_cost_cents_max = 9200;
break;
case "WAV":
estimated_cost_cents_max = 9200;
break;
case "ASSIST":
estimated_cost_cents_max = 9200;
break;
case "uberXL":
estimated_cost_cents_max = 14800;
break;
case "SELECT":
estimated_cost_cents_max = 20900;
break;
case "SUV":
estimated_cost_cents_max = 30600;
break;
}
return estimated_cost_cents_max;
}
};
var uberFuture = CompletableFuture.supplyAsync(() -> uber.getFareEstimate(start_lat, start_lng, end_lat, end_lng, "uberX"));
// compare the futures for best fare estimate
Stream.of(lyftFuture, uberFuture)
.map(CompletableFuture::join)
.min(Comparator.comparing(i -> i))
.ifPresent(estimated_cost_cents_max -> System.out.println("$" + estimated_cost_cents_max / 100));
}
}

view raw

RideTest.java

hosted with ❤ by GitHub

If you look at this example carefully, you’ll see our IntelliJ Lambda inspection kicks in for our anonymous inner class.

Screen Shot 2018-01-10 at 9.08.33 PM

I replaced it with lambda, but it did not keep IntelliJ happy (of course, this is experimental!).

Screen Shot 2018-01-10 at 9.12.19 PM

This one turned out to be a bug in inspection and it has been since fixed.

Support for Lambda Parameters is coming. In fact, there is an experimental support for this feature in lvti branch in amber repository. Maurizio explains the details in this post.

Happy learning folks!

One thought on “Local Variable Type Inference in Java 10

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s