Back
August 19, 2020

After Java 8: Part 3 — Java 10

Share:

This is the third in a series of articles about changes in Java ecosystem after version 8. In the previous article, we covered changes in java 9. In this article, we will discuss changes in the language that came with version 10.

Java 10 is released in March 2018, it is non LTS release with the end of support in September 2018 for Oracle Open JDK and Oracle JDK. It is the first release in the new 6 months release cycle and therefore contains only minor, incremental changes.

Local variable type inference

Java 10 introduced var as a reserved type name that can be used to initialise local variable without declaring it explicitly. The idea of var is to reduce boilerplate code and increase readability.

//declaring variable explicitly
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("path/file"));//using var
var someString = "someString";

At compile time, the compiler infers a type based on the initialisation statement.

//var after compilation 
String someString = "someString";

From Java 10, creating class or interface with name var is not possible because var is a reserved type name. However, class or interface with name Var (upper case ) can be created.

public class var {
//compile error: var cannot be used for type declarations
}
public class Var {
//compiles successfully
}

How var cannot be used in code:

  • var cannot be used as a field type, method parameter type or constructor parameter type.
  • Because var is a reserved type name, methods and fields can be named var
class SomeClass {
private int var;
public void var() {
}
}
  • var must be initialized
//compile error, var must be initialised
var x;
  • var cannot be referenced to a null
//compile error, cannot infer type, var initialiser is null 
var x = null;
  • var is not allowed in a compound declaration.
//compile error, cannot infer type
var i, j =0;
  • var cannot replace the type of lambda expression

var lambda = x -> x > 3

How to and how not to use war:

Think twice before using it. Does it really add to readability off your code?

If you decide to use it, here are some advices that can help you to use it better, and to annoy the person who will be doing maintenance of that code a little bit less:

  • Choose a good variable name
var x = dbConnection.executeQuery(query);  //bad examplevar users = dbConnection.executeQuery(query); //good example
  • Use good initializer information
var user = get();  //bad examplevar users = getUsers(); //good examplevar user = getUser(); //good example
  • Take care with <>
var users = new ArrayList<>();  //bad example - ArrayList<Object> is inferredvar users = new ArrayList<User>(); //good example - ArrayList<User> is inferred
  • don’t use var for initialising anonymous object
var object = new Object(){} // the type of the object variable is Object$1 extends Objectobject = new Object(); // won't compile, object type isn't compatible with Object$1 which is inferred type of the variable
  • intersection types
var list = List.of(1, 2.0, "3");// type => List<Serializable & Comparable<? extends Serializable & Comparable<?>>>

OrElseThrow

Java 8 introduced Optional API for preventing the NullPointerException by wrapping the object that we suspect may be null. Java 10 introduced orElseThrow() method which can be called on object type Optional and it will throw NoSuchElementException if object inside the Optional is null.

Optional<String> optional = Optional.empty(); optional.orElseThrow() // Will throw NoSuchElementException

APIs for creating unmodifiable collections

Java 10 added List.copyOf, Set.copyOf, Map.copyOf for creating the unmodifiable collection with copied instances of other collection

Difference between Collections.unmodifiableList(cars) and List.copyOf(cars)

Also, unmodifiable collection can be created from stream using Collectors.toUnmodifiableList, Collectors.toUnmodifiableSet, Collectors.toUnmodifiableMap

Other improvements

Graal compiler is written entirely in java (unlike C1 and C2 compilers that are written in C). Since it uses JVM Compiler Interface to communicate with VM it can be used with both HotSpot VM as well as Graal VM. More about GraalVM and Graal Compiler: https://www.graalvm.org/ , https://github.com/oracle/graal/

-XX:+UnlockExperimentalVMOptions 
-XX:+EnableJVMCI
-XX:+UseJVMCICompiler
  • G1GC improvements

Mainly introduction of full parallel processing during a Full GC. This change won’t help the best-case performance times of the garbage collector, but it does significantly reduce the worst-case latencies.

  • Thread-local handshakes

During serviceability operations, like collecting stack traces for all threads or performing garbage collections, when the JVM needed to pause one thread, it needed to stop them all. Sometimes, these are referred to as “stop-the-world” pauses. This was due to the JVM wanting to create a global safepoint from which all application threads could begin again once the JVM was done. In Java 10, though, the JVM can put an arbitrary number of threads into a safepoint, and threads may continue running after performing the prescribed “handshake”. The result is that if the JVM can pause just one thread at a time, whereas before it had to pause them all.

  • Container awareness

Before java was not container aware. So, in case you had you java app running in Docker, and for some reason you didn’t set max heap size on app startup, JVM would allocate 1/4 of memory available on host. So, in case you had 10 docker containers running on the same host, and each of them taking 1/4 of available host memory things will go wrong quite fast.

Now, if you wish to have your app aware of space allocated to container where it runs, you should pass following params on startup:

-XX:+UseCGroupMemoryLimitForHeap
-XX:ActiveProcessorCount=xy

Where xy is number of processor cores that container is using.

  • Alternative memory allocation

-XX:AllocateHeapAt=<path>


Share: