Modern Java Development

2021 03 01 head

Java development activities have won traction since the decision to release a new version to the community every six months. Preview and incubator features promote feedback from the community and users.

Some tool builders, such as JetBrains are working proactively and provide support for JDK in developments.

Other tool maintainers such as JaCoCo are dreadfully behind the release cycle.

We learnt to deal with the new speed and how to tackle the laggards. Some experiences were quite painful.

Below are our findings and our current focus on developing software products.

Legibility Matters

Programmers learnt in the last decade that legibility and brevity of programming languages matter. The Java Coin and Amber projects were initiated to reduce the verbosity of the Java language mainly through syntactic sugar. A programmer should not be forced to write statements the compiler could infer.

Examples of improvements are

  • Diamond operators to avoid writing two times the same generic parameter declarations,

  • Try with resources to avoid complicated finally blocks to close resources,

  • Multiple catch of exceptions to avoid writing multiple times the same error handling block,

  • var local variables to avoid complex declarations of local variables,

  • default methods in interfaces to avoid declaring the same method in multiple classes,

  • Strings as switch selector to write readable code instead of huge if statements,

  • Underscore in numerical constants to increase legibility.

Deeper changes are

  • The new date API is simplifying the handling of date and time logic. The solution is based on the learning of the Joda time library.

  • Support of Lambda constructs greatly eliminates the need for verbose anonymous classes.

Useful Constructs

Modern Java has introduced powerful constructs to write legible and maintainable code. Modern Java code is quite different from Java 5 code.

Java Modules

Dependency management is supported at language level.
The Ada programming language has support for module since 1985.

Streams and Lambda

Support for functional programming approaches. Streams are declarative and support internal iterators.
The Booch Ada component library has supported internal iterators since 1985.

Record

Very compact notation to define a data class and transparent handling of properties. Records are immutable objects and finally use modern naming for getters [1].

Sealed Types

Interesting way to restrict inheritance to a set of selected classes. Very helpful for library designers. You can publish an interface in the public API and limit the classes implementing this interface[1].

Reflection versus Lambda

References to methods and constructors are part of the lambda extension. The LambdaMetafactory class allows you to create a reference at runtime. The reflection operations can be replaced by lambda expressions. The code is more performant and has security issues.

Text Blocks

We can finally write legible multi-line strings.

Cumbersome Aspects

We still have open wounds in the legibility and elegance of the Java programming languages.

  • Unsolved legibility problems through annotations polluting your domain model.

  • Null values (and the missing of an Elvis Operator or a Null Coalescing Operator).

  • Fluent interface when setting multiple properties in an instance.

  • Missing support for modifiable properties (read-only properties have initial support in the record construct).

  • Missing logging interface similar to slf4j.

  • Reified generics to have access to generic types during runtime.

Next Improvements?

We have the first signs of possible improvements.

A more concise notation for getters and setters

The record extension finally provides a more concise and legible convention for getter and setters. I hope the convention will be used in all new library classes.

Type property();
void property(Type property);
Stop using checked exceptions and replace them with runtime exception

Lambda expressions cannot handle checked exceptions. Only runtime exceptions can be thrown in a lambda expression. Experience with other programming languages shows that checked exceptions do not provide gains in the quality of delivered code.

Pattern matching with deconstruction

First, pattern matching constructs are available in switch and if statements. Discussions are underway to extend pattern matching with object deconstruction.

Value Types

Value types would be a huge improvement in performance and support of modern processor architecture if the Valhalla product delivers.

The only drawback we have with modern Java development is the sluggish catch-up of open-source tools and libraries. For example Gradle Build Tool needed five years to provide module support in the Java plugin. Gradle 6.4 was the first version really supporting Java modules.


1. Records and Sealed Types are the Java implementation for Algebraic Data Types.