Ever since Java 8's introduction of lambda statements, Java has been releasing more language updates on every major version release. From Java 9's Jigsaw (Java Platform Module System), Java 10's local variable inference using var
, to the preview features in the current Java 14. More and more language features are coming to Java to promote better coding and architecture designs.
With all of these feature that was introduced in the previous Java versions, there are still a ton of feature yet to come in future releases!
Here are the upcoming Java Language features that I look forward to!
Just some disclaimers: Remember that these features are not yet released. Some of the examples shown here are subject to change when the feature is actually released. Additionally, some of the features here are only available as JDK Enhancement Proposal (JEP) or hidden in the JDK that can only be enabled by using --enable-preview --source 14
JVM flag in javac
and java
commands. At the time of writing, Java 14 is the latest JDK release and I can only test language features that came with it.
Records
Value-based classes or record
is planned to be released in Java 15, but already usable in Java 14 by enabling the preview flag.
Record is another way to define a type in addition to class
, interface
, and enum
. This type represents a data class that cannot be extended by a subclass.
To create a record, we need to use the new record syntax:
A record instance can be created just like how we create objects. The difference of a record from a data class is that records are always immutable and its accessors does not start with the word get
.
In the above example, you can notice that the tuple used to declare the fields of the record becomes the constructor of the record. The field name also became the accessor name. Based on my experience with records, this is a problem when using frameworks that expects a get-
style accessors. This problem can be worked-around by creating a custom getter method in the record:
public record Keyboard(
String name,
String switchName
) {
public String getName() {
return name;
}
public String getSwitchName() {
return switchName;
}
}
That does the job for backwards compatibility, but I think doing so loses the record's purpose to reduce boilerplate code for data classes.
Pattern Matching
This is another preview feature that can only be used by enabling the preview flag. Pattern matching simplifies data type checking. This is not really a big syntax update, but it helps a lot. This language feature is particularly useful when defining your own equals()
method or when making a factory that is based from data types.
Switch Expressions
Actually this feature is already available in Java 14, but I haven't used it yet in a project. Also, since Java 14 is not an LTS release, we expect that this will replaced in upcoming Java versions and will be production ready only on Java 17, which is the next LTS release.
What's more fun in switch expressions is that there are more incoming Java features that will extend the power of this langauge feature.
For now, let's see what does this do.
As the name suggest, the switch expression syntax makes the classic switch
statement into an expression. This works much like SQL's case...when
statement.
In the classic switch
statement, each case
block holds their own set of statements and ends with the break;
statement to prevent statements from the next case
blocks from executing.
In the example above, we can see that the swtich
statement has gone smaller due to the disappearance of some of the statements from the classic switch statement.
Differences between classic switch statement and the new switch expression
- The symbol to stop the test value has been changed from colon
:
to arrow->
. When using the arrow symbol, it tells the compiler that you are doing a switch expression. - No need for
break
statement. The result of a switch expression is, of course, the evaulation of the expression at the right side of the->
symbol. This language feature is not intended to execute multiple statements percase
. - The
default
case is not always required. When switching between enum values, thedefault
case is not needed when all of the enum values are exhausted from the existingcases
. - The evaluated value can be assigned to a variable. No need to declare an uninitialized variable above the
switch
statement only to be initialized in one of the cases in theswitch
.
Pattern Matching in Switch Expression
I haven't tried this language feature yet, but I have already seen it in its JEP and in this YouTube video.
As the name suggest, this language features enables us to test multiple data types in a switch
statement.
This language feature will be very useful when doing a type-specific action.
Helpful NPE Message
Ok, this is not really a Java language feature but I think this is one of my favorite updates in Java 14. This feature is disabled by default and can be enabled by adding the -XX:+ShowCodeDetailsInExceptionMessages
argument. In Java 15, this feature will be enabled by default.
When this feature is enabled, the error message for NPE's will change to a more natural, english-like sentence that actually tells you which field is the cause of the NullPointerException
.
Consider the following source code:
When you run that program, this is the error message you will get:
Note: ./HelpfulNpe.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
Exception in thread "main" java.lang.NullPointerException
at HelpfulNpe.main(HelpfulNpe.java:4)
This is the classic NPE message that only shows us the line number the error came from.
Now, this is the NPE message when the -XX:+ShowCodeDetailsInExceptionMessages
is enabled.
Note: ./HelpfulNpe.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because the return value of "User.name()" is null
at HelpfulNpe.main(HelpfulNpe.java:4)
Notice that the message now shows what method call caused the NPE and additional explaination on why that happened.
Honorable Mentions
Record Destructuring
This is a language feature that enables us to assign members of a record
to multiple variables. Since Java is a strongly-typed language, this feature is only usable with pattern matching using if
statement or switch
statement.
record Keyboard(String name, KeyboardSwitchType switchType) {}
// ...
var keeb = fetchKeyboard();
if (keeb instanceof Keyboard(var name, var type)) {
System.out.println("Name: " + name);
System.out.println("Type: " + type);
}
Multiline Strings / Text Blocks
This is a preview feature available in Java 14. It enables us to write multiline strings using the triple-double quote symbol """
. This is very useful when writing an embedded code in your Java code (like SQL or HTML). Unlike the multiline strings in other languages like Groovy, this language feature is smart enough to detect indentation in the Java source code and ignore them when evaluating the string value.
String sql = """select *
from users
where deleted = false
and name like :filter
"""
When the string from the example above is evaluated, the word from
will be aligned from the word select
from the first line. It will not have 16 spaces before it just because it has 16 spaces in the raw Java code.
In other words, the resulting string will be like this:
select *
from users
where deleted = false
and name like :filter
and not like this:
select *
from users
where deleted = false
and name like :filter
Sealed Interfaces and Abstract Classes
This is a preview feature that will be enabled on Java 15 release. Using sealed
and permits
keywords to an interface
or abstract class
declaration prevents implementing or extending the sealed type.
public sealed interface PointingDevice
permits Mouse, Touchpad, Trackball {
// interface contents...
}
public class Mouse implements PointingDevice { }
public class Touchpad implements PointingDevice { }
public class Trackball implements PointingDevice { }
In the above example, the interface PointingDevice
can only be implemented by Mouse
, Touchpad
, and Trackball
. One of the biggest use case of this language feature is its exhaustiveness when used in a switch
statement, just like enums!
Local Methods
This is a preview feature that might be enabled on Java 15 or 16 release. Basically, this language feature enables us to declare methods inside a method. Just like local variables, this method is not known outside the method it's declared from. I'm not really a fan of this since private
method already does the job right with proper code architecture. Nevertheless, this is an interesting feature to watch out for!
Conclusion
The Java language is evolving fast! Since the process to improve Java is open, we can see the language features that is yet to come.
Since some of the feature are almost complete, and some are already hidden in the current JDK distributions, we can now test and see the incoming language features. Here are some of my favorites:
- Data class – The new
record
class enables us to write concise data classes, just like lombok's@Data
annotation. The only difference isrecord
is a native syntax and no 3rd party JAR files required. - Pattern Matching – Very useful on architecture that uses a lot of inheritance. This makes type checking more concise.
- Switch Expression – A simple but powerful update to the classic
switch
statement. Now thisswitch
statement allows us to assign its result to a variable. In future versions of Java, switch expressions will also allow pattern matching, destructuring, and exhaustive evaluation of sealed types. - Helpful NPE Message – This is the only non-language feature that I included in this list. I think this is very powerful debugging tool since it points directly where the NPE exactly came from instead of telling us just the line number.
Other than these, I also look forward to other incoming Java language features such as destructuring, multiline strings, sealed types, and local methods.