Java18 is coming soon, and many of you are still using Java8 and may not be aware of many of the features that are available in the higher version. Here are some of the features that I think are useful from Java9 to Java17 to give you more reasons to upgrade your company’s Java version.
It is possible that many companies will refuse to upgrade a later version of the JDK for “stability”, just as people who were using JDK1.6 refused to upgrade when Java8 was first released. But who knows how much of it is really about stability and how much is just companies rejecting new technologies? ^ _ ^
Some of the features
JEP 286: Local Variable Type Inference (Java11)
Variable type derivation allows us to define a variable using the var keyword when using local variables:
var list = new ArrayList<String>();
Copy the code
This is one of my favorite and most commonly used features, which can significantly simplify code, but also brings a problem: decreased readability. How should use, see individual weigh.
JEP 358: Helpful NullPointerExceptions (Java14)
I believe that most people will encounter a headache when dealing with NPE, that is, the NPE line is a chain call, such as:
class Main {
public static void main(String[] args) {
var x = a().b().i.j;
}
}
Exception in thread "main" java.lang.NullPointerException:
at Main.main(Main.java:3)
Copy the code
Such NPE anomalies are so nondirectional that you may not even know which method or variable is reporting the anomaly. In Java14 and beyond, the NPE will become more directional, the same code, and the exceptions in Java14 will be:
Exception in thread "main" java.lang.NullPointerException:
Cannot read field "j" because "i" is null
at Main.main(Main.java:3)
Copy the code
This allows us to identify problems more clearly when troubleshooting them.
JEP 361: Switch Expressions (Java14)
More elegant and concise Switch expressions, no need to write a bunch of CASE/BREAK
switch(month) {
case 1.3.5.7.8.10.12 -> System.out.println("31");
case 4.6.9.11 -> System.out.println("30");
case 2 -> System.out.println("28");
};
Copy the code
Switch can also be used as an expression, that is, to provide a return value:
var x = switch(condition) {
case A -> "a";
case B -> "b";
default -> "none";
};
Copy the code
The new yield keyword also allows you to process large blocks of code in an expression:
var x = switch(condition) {
case A -> "a";
case B -> "b";
default -> {
Sytem.out.println("in default");
//do something else
varresult = doSomething(); yield result; }};Copy the code
JEP 378: Text Blocks (Java15)
Finally, finally, not having to deal with a bunch of antislant, \n, + splices in strings!! A quick comparison:
var script = "function hello() {\n" +
" print('\"Hello, world\"'); \n" +
"}\n" +
"\n" +
"hello(); \n"
Copy the code
Java15 and later:
var script = """ function hello() { print('"Hello, world"'); } hello(); """
Copy the code
Readability is so different that such a simple, common base capability should have been provided long ago! You can also use placeholders and format methods just like normal strings.
JEP 395: Records (Java16) data class, somewhat similar to Kotlin’s Data Object. You can define a data class as follows:
public record Data(int x, int y) {}Copy the code
This class implements hashCode(), equals(), and toString() methods by default, and is defined as final and immutable: fields cannot be modified after initialization. It is also possible to define normal or static methods within a class.
When we need to return some immutable data for external use, we can use Record to define the data format. After SpringBoot 2.5.0-M1 (or upgrade Jackson), Java16 support is also available, which means you can use it in some spring scenarios. For example, when a Controller receives a parameter, the parameter can be a Record class.
JEP 394: Pattern Matching for Instanceof (Java16)
Pattern matching, or type matching, which is already available in Kotlin, allows us to do less casting when coding:
if (obj instanceof String) {
String s = (String) obj;
s.toLowerCase();
}
Copy the code
Java16 and later:
if (obj instanceof String) {
Automatic type derivation
obj.toLowerCase();
}
// Even so
var isGood = obj instanceof String && obj.trim().toLowerCase().equals("good");
Copy the code
Well, in some cases, casting can be cumbersome all the time, so this feature can at least reduce some of the coding effort.
JEP 409: Sealed Classes (Java17)
Providing a new constraint to a class or interface may not be useful in a general situation, but it is useful when we need to write a framework, or when we need to write an SDK for other departments or users. Here’s an example:
public abstract sealed InnerAbsClass permits InnerClassA, InnerClassB {
}
Copy the code
When a class is sealed, only names with permits can inherit an abstract class. Other classes that attempt to inherit an abstract class will be reported at compile time.
An additional way is to exclude permits, so subclasses can only be defined within the same file:
public abstract sealed InnerAbsClass {
}
public final InnerClassA extends InnerAbsClass {}
public final InnerClassB extends InnerAbsClass {}
Copy the code
Interfaces can be defined in the same way.
Why not use “package access” to restrict inheritance or implementation? There are some scenarios where we want the parent class not to be inherited by external users, but we also want it to be accessible, such as providing static variables and static methods that can be used externally.
conclusion
This isn’t all of them, but there are some features THAT I’ve actually used and found to be useful, some that improve productivity, and some that people who are using lower versions of Java might see and decide to push their companies to upgrade. Java17 is a long-term release from Oracle, with support up to September 2029. Support for up to eight years will at least guarantee its stability.
In the end, it’s okay to pursue stability, but it’s okay to embrace change