The Ultimate Guide To Java 15

An Overall Introduction To The Most Effective Updates Among Java 14 And Java 15

Maurizio Natalia
ITNEXT

--

Photo by Michiel Leunens on Unsplash

Java is nowadays one of the worldwide spreadest programming languages with its Java SE 8 released on March 18, 2014 and that counts about 60% of usage in the main applications.

Java 14, and then Java 15, have been released respectively on March 17 and September 15 2020 increasing features for developers.

Let’s have an overview of the main JEP (Java Enhancement Proposal) for each release.

Java 14: Pattern Matching for instanceof (JEP 305), Helpful NullPointerExceptions (JEP 358), Records (JEP 359), Switch Expressions (JEP 361), Text Blocks (JEP 368)

Java 15: Sealed Classes or Interfaces(JEP 360)

Java 14

Pattern Matching for instanceof

Each Java programmer should know the older syntax used to define an instanceof block. It foresaw three main steps: test, declaration of new variable and a conversion (casting obj to String)

if (obj instanceof String) {
String s = (String) obj;
// use s
}

The istanceof operator is now extended to take a type test pattern instead of just a type. In the example below, YourClass y is the type test pattern.

As you can notice, the new instanceof operator allows you to test, declare and cast variables in a single step. Obviously, you can use the newly declared variable right away!

This kind of syntax simplifies the implementation of methods too. Take a closer look at the equals() and multiply() methods in the snippet above.

Helpful NullPointerExceptions

A NullPointerException (NPE) is thrown by the JVM when a program tries to dereference a null reference. Basically, this enhancement wants to improve the usability of NPE generated by the JVM by describing precisely which variable was null. Now, consider we have the following assignment expression:

a.i = 99

…and consider that a is null. The execution will cause the JVM to print out the method, filename, and line number that caused the NPE.

Exception in thread "main" java.lang.NullPointerException
at Program.main(Program.java:5)

With the release of Java 14 and the JEP 358 the message will be:

Exception in thread "main" java.lang.NullPointerException: 
Cannot assign field "i" because "a" is null
at Program.main(Program.java:5)

In the more complex statement:

a.b.c.i = 99Exception in thread "main" java.lang.NullPointerException: 
Cannot read field "c" because "a.b" is null
at Program.main(Program.java:5)

Records

Everybody knows that Java is really too verbose. In my opinion, records are one of the best enhancement of ever specifically for classes that are simply data aggregators or carriers gaining an extreme level of concision being represented just by a name and a state. The state declares the components of the record.

A record will implicitly define:

  • A private final field for each component of the state description
  • A public read accessor method for each component of the state description
  • A public constructor with the same signature of the state description
  • Implementation of equals(), hashCode() and toString() methods

Which are the restrictions on records?

  • A record cannot extend any other class
  • A record cannot declare instance fields other than the final fields in the state description
  • Any other declared field must be static
  • A record is final (it cannot be extended by other classes or records) and cannot be abstract

In the end, speaking about annotations: they can be used on record components if they are applicable to record components, parameters, fields, or methods.

Switch Expressions

In general, a switch block allows the application to have multiple possible execution paths based on the result of an expression in runtime.

With Java 14, switch expressions have been extended introducing a lot of new interesting feature.

Let’s write down just the old method used to define a block expressions:

switch(expression) {
case a:
// code block
break;
case b:
// code block
break;
default:
// code block
}

In the JEP 361, a new form of switch label has been introduced: “case a ->”. This means that only the code to the right of the label is to be executed if the label is matched.

The new version of the previous snippet of code, becomes

switch(expression) {
case a -> // code
case b -> // code
default -> // code
}

Going forward, switch statement has been extended so it can be used as an expression. In the most generic form, a switch expression looks like:

T result = switch(expression) {
case label1 -> expression1;
case label2 -> expression2;
default -> expression3;
}

Yielding a value

Whenever a full block is needed instead of a single line expression, a new keyword yield has been introduced to yield a value. The previous statement becomes:

T result = switch(expr) {
case label1 -> expression1;
case label2 -> expression2;
default -> {
expression3;
expression4;
yield result;
}

It’s really important to keep in mind the following clause:

The two statements, break (with or without a label) and yield, facilitate easy disambiguation between switch statements and switch expressions: a switch statement but not a switch expression can be the target of a break statement; and a switch expression but not a switch statement can be the target of a yield statement.

It means that the yield keyword is used just to return a value from a full block code; the result that has to be assigned to a variable.

So, at the end, I want to report one more other example of new featured switch statement used as an expression inside a syso call:

static void isEven(int k) {
int e = k % 2;
System.out.println(
switch (e) {
case 0 -> true;
case 1 -> false;
default -> "WTF";
}
);
}

Text Blocks

Welcome, Text Blocks! From now, developers can define strings that span several lines of source code (e.g. HTML, SQL query) avoiding escape sequences enhancing readability such as in Python. An example could be the following:

String query = """
SELECT `PERSON_ID`, `NAME` FROM `PERSONS`
WHERE `AGE` > 35
ORDER BY `PERSON_ID`, `NAME`;
""";

Java 15

Sealed Classes or Interfaces

Sealed Classes (or Interfaces) are an interesting feature introduced in Java 15 with the JEP 360. Obviously, the purpose of inheritance is not only to reuse code but even to model the various possibilities that exist in a domain.

Sealed Classes or Interfaces restrict the set of which other classes or interfaces can extend or implement them through the keyword permits.

To give an example, we can decide to define an abstract class Animal and to model the domain just with Reptiles and Amphibians such as the code snippet below.

--

--