To Java 11 and beyond - Part 2

To Java 11 and beyond - Part 2

In this second installment of this blog series, I’ll take a look at some of the features introduced in Java 11 we haven’t looked at previously. After this, I reflect on what we have learned throughout this blog series and share some of my opinions about the release cycle.

JEP 213 Interface evolution via virtual extension methods Milling Project Coin

Since Java 9, we are able to use private methods and private static methods inside our interfaces. This addition improves code re-usability inside our interfaces. For example, we can abstract common logic for multiple default methods into such a method. This way we adhere to the don’t repeat yourself (DRY) principle, while simultaneously preventing unneeded exposure of this logic.

To use these private methods, we have to keep the following rules in mind:

  1. A private interface method cannot be abstract
  2. The private method can only be used inside the interface
  3. Private static methods can be used inside other static and non-static interface methods
  4. Private methods cannot be used inside private static methods
  5. The private methods must contain a body

Following is an example of exactly how you could go about abstracting logic used in multiple places within private interface methods.

public interface PrivateMethodInterfaceTester {
  default void printHello(){
    printMessageDelegation("hello");
  }

  default void printBlog(){
    printMessageDelegation("blog!");
  }

  private void printMessageDelegation(String message) {
    printMessage(message);
  }

  private static void printMessage(String message) {
    System.out.println(message);
  }
}

Conclusion

While this might not be the most shocking of features that is introduced, this focus on design patterns is refreshing to see and is a trend I personally hope to continue seeing in future releases.

JEP 323 Local-variable syntax for lambda parameters

As far as features go, this is the only actual language feature introduced in Java 11. However, it does build upon Local Variable Type Inference introduced in Java 10 under JEP 286.

Local Variable Type Inference introduced the much requested var reserved word for local variable instead of a predefined manifest type. Here, type inference is the ability of Java’s compiler to look at method invocation and the corresponding declaration to determine the type argument that makes the invocation legal. For example, the following code produces equivalent byte code:

List<Person> personList = List.of(new Person()); // Java 8

var varPersonList = List.of(new Person()); // how we could write this in Java 10 onwards.

However, this does not mean Java is becoming dynamic. It’s just some syntactic sugar to allow this implicit way of writing your local declarations.

Note here that var is not a keyword. Because of this we maintain the ability to use “var” as a variable, method or package name. This approach is similar to the reserved words we’ve seen throughout the module system. Due this, it’s perfectly legal to do the following:

public void var() {var var = "var"} //please don’t actually do this

This choice makes sense, seeing how the usage of var is scoped to local variable usage only, paired with limited use-case scenarios:

That being said, JEP 323 adds another use case, using it as a formal parameter of an implicitly typed lambda expression like this:

BiFunction<String, Integer, String> stringBiFunction = (var string, var integer) -> string + integer; 

This might feel unintuitive, as a type definition is optional within a Lambda. However, this does allow us to use Annotations like @nullable without explicitly declaring the parameter type.

BiFunction<String, Integer, String> stringBiFunction = (var string, @Nullable var integer) -> string + integer;
    

Note that using var in this sense still requires us to either type all or none of the lambda parameters.

The focus on Garbage collecting

JEP 248: Make G1 the Default Garbage Collector

While the ‘Garbage-First’ garbage collector (G1) has been a part of the JDK since the introduction of Concurrent class unloading (JEP 156) in Java 7, it’s considered as a fully-featured garbage collector, which caused this change to happen in Java 9.

The big difference the G1 collector introduces, compared to the collector Concurrent mark sweep collector (CMS) used up until Java 9, is that it focuses on minimizing pause times, without constraining the heap size or the amount of live data. This is achieved by doing a large chunk of the GC work concurrently paired with doing partial compaction. Avoiding doing full GCs (i.e., stop-the-world GCs) is one of the major benefits of G1.

JEP 304: Garbage Collector Interface

Another change we see in the Java 11 LTS is the, in Java 10 added, Garbage Collector Interface. This improves the modularity of the HotSpot JVM. Before this introduction, garbage collector code was scattered all over the hotspot sources. This introduces a few progress blocking problems:

  1. Implementing a new GC requires knowledge about all these aforementioned places, as well as implementation details about the various classes for specific needs.
  2. Furthermore, this knowledge was already required for removal or exclusion of a GC at build time.

Due to these problems, adding a new garbage collector used to be a difficult task.

With this new interface, this should be just a matter of implementing a well defined set of interfaces.

While the main goal of the JEP wasn’t to actually add or remove any GC’s, it proves to be helpful for the JEP’s where this is the goal, as for example JEP 318 JEP 318: Epsilon: A No-Op Garbage Collector (Experimental), which is also included in Java 11.

Conclusion

Due to the changed release cycle, we are seeing Java seeking for more feedback from the Java community in the form of incubator Modules, introducing concepts quickly and building upon these concepts.

This phased way of releasing features, as opposed to the old release cycle with pressure to finish a set of features due to the timespan between releases, answers an important question; “How does Java plan to survive the next decade of software development”. Personally, seeing this Agile-like approach being introduced brings confidence that Java is trying to change their pace according to the change of the market. That being said, the upcoming years will be pretty critical years for Java. These changes mean very little if the gross of important enterprise products or important products are unable to get off Java.

In the meantime, we start seeing more Java developers write about their wishes for the future of Java within the community. While this can’t be seen as an absolute evaluation, it does indicate that the community is getting more motivated. It’s also important to keep in mind that, especially for innovators regarding Java, there are more opportunities than ever before to try out new features. Java 12, 13, Jakarta EE and so on. All of which have been claimed to be striving for innovation.

All in all, as a developer the release cycle feels significantly more transparent than before and motivates me to keep an eye on the Java proposals to create a good understanding of what we can expect from Java 17, the next LTS release. It also took some of my doubts away whether the language would slowly march to a state of being undead, an unfortunate fate that has bestowed many languages like cobol, arguably PHP and others. One thing is for sure, we expect a lot of exciting features added to Java as the general IT field evolves.

Please note that this article takes a curated list of features that stood out amongst the rest of them. There are more changes between the LTS releases that haven’t been mentioned, including deprecations, new member methods for String objects, etc. That’s why we would like to motivate you to have a look at other resources before making a concrete decision about whether Java 11 would add value to relevant environments.

(All examples have been tested with Java version 11.0.4)

Alex van der Wal
Alex van der Wal

Java Developer