Table of Contents
14.1. Switch Expressions
Switch Expressions after staying a preview feature in the last two releases –Java 12 and Java 13 have finally attained permanent status in Java 14.
- Java 12 introduced the lambda syntax for switch expressions thereby allowing multiple case labels for pattern matching as well as preventing fall-throughs which lead to verbose code. It also enforced exhaustive cases wherein a compilation error would be thrown if all the input cases aren’t covered.
-
Java 13, the second preview introduced
yield
statements instead ofbreak
for returning values from an expression.
Java 14 has finally made these features a standard now.:
String result = switch (day) { case "M", "W", "F" -> "MWF"; case "T", "TH", "S" -> "TTS"; default -> { if(day.isEmpty()) yield "Please insert a valid day."; else yield "Looks like a Sunday."; } }; System.out.println(result);
14.2. Pattern Matching for instanceof (Preview)
Ask any Java developer to show their codebase and you’ll a good use
of instanceof
conditions throughout the code. Specifically, an instanceof
conditional check is generally followed by a typecasting
Java 14, gets rid of this verbosity by making conditional extraction a lot more concise.
Before Java 14:
if (obj instanceof Journal { Journal jd = (Journal) obj; System.out.println(jd.getAuthor()); }
Java 14 Onwards::
if (obj instanceof Journal jd) { System.out.println(jd.getAuthor()); }
In the above code, the instance jd
would be only assigned if obj
is of type Journal
. The scope of the variable is limited to the conditional block
only.
14.3 Helpful NullPointerExceptions
Null Pointer Exceptions are a nightmare for any developer. Previously, until Java 13, it was tricky to debug the infamous NPEs. Developers had to fall onto other debugging tools or manually figure the variable/method that was null since the stack trace would only show the line number
Before Java 14:
String name = jd.getBlog().getAuthor() //Stacktrace Exception in thread "main" java.lang.NullPointerException at NullPointerExample.main(NullPointerExample.java:5)
Java 14 introduced a new JVM feature which gives better insights with a more descriptive stack as shown below::
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Blog.getAuthor()" because the return value of "Journal.getBlog()" is null at NullPointerExample.main(NullPointerExample.java:4)
Note: The above feature is not a language feature. It’s an enhancement in the runtime environment.
14.4. Records (Preview)
A record is a data class that stores pure data. The idea behind introducing records is to quickly create simple and concise classes devoid of boilerplate code.
Normally a class in Java would require you to implement equals()
, hashCode()
, the getters and setters methods. While some IDEs support
auto-generation of such classes, the code is still verbose. With
a record
you need to simply define a class in the following way
record Author(){} //or record Author (String name, String topic) {}
The Java compiler will generate a constructor, private final fields,
accessors, equals
/hashCode
and toString
methods automatically. The auto-generated getter methods of the
above class are name()
and topic()
.
To look into the generated code, use javap Author
after you’ve compiled the program using javac
. The following illustration shows the generated class for record Author (String name, String topic) {}
:
The semantics of Records is similar to Data Classes in Kotlin
Furthermore, we can add additional fields, methods, and constructor to the record in the following way:
record Author (int id, String name, String topic) { static int followers; public static String followerCount() { return "Followers are "+ followers; } public String description(){ return "Author "+ name + " writes on "+ topic; } public Author{ if (id < 0) { throw new IllegalArgumentException( "id must be greater than 0."); } } }
The additional constructor defined inside the record is called a Compact constructor. It doesn’t consist of any parameters and is just an extension of the canonical constructor
A compact constructor wouldn’t be generated as a separate constructor by the compiler. Instead, it is used for validation cases and would be invoked at the start of the main constructor.
Few important things to note about Records:
- A record can neither extend a class nor it can be extended by another class. It’s a final class.
- Records cannot be abstract
- Records cannot extend any other class and cannot define instance fields inside the body. Instance fields must be defined in the state description only
- Declared fields are private and final
- The body of a record allows static fields and methods
14.4.1 Values Inside Reference Fields Of A Record Can Be Mutated
It’s important to note that for fields defined which are objects, only the reference is immutable. The underlying values can be modified. The following illustration shows a record in which the ArrayList is modified. As you can see, the value is modified whenever the ArrayList is changed.
14.4.2 Records Can Implement Interfaces
The following code shows an example of implementing an interface with recordsint[] a = {1, 2, 3, 4};
record Author(String name, String topic) implements Information { public String getFullName() { return "Author "+ name + " writes on " + topic; } } interface Information { String getFullName(); }
Here’s the output of the above code in action in a JShell
14.4.3 Records support multiple constructors
Records allow declaring multiple constructors with or without parameters as shown below::
record Author(String name, String topic) { public Author() { this("NA", "NA"); } public Author(String name) { this(name, "NA"); } }
14.4.4 Records Allow Modifying Accessor Methods
Though records do generate public accessor methods for the fields defined in the state description, they also allow you to redefine the accessor methods in the body as shown below::
record Author(String name, String topic) { public String name() { return "This article was written by " + this.name; } }
14.4.5 Check Record and its Components at Runtime
Records provide us with isRecord()
and getRecordComponents()
to check if the class is a record and also look into its fields and
types. The following illustration shows how it is done:
14.5. Text Blocks (Preview)
Text Blocks were introduced as a preview feature in Java 13 with the goal to allow easy creation of multiline string literals. It’s useful in easily creating HTML and JSON or SQL query strings.
In Java 14, Text Blocks are still in preview with some new additions. We can now use:
Backslash for displaying nice-looking multiline string blocks.\s
is used to consider trailing spaces which are by default ignored by
the compiler. It preserves all the spaces present before it.
-
String text = """ Did you know \ Java 14 \ has the most features among\ all non-LTS versions so far\ """; String text2 = """ line1 line2 \s line3 """; String text3 = "line1\nline2 \nline3\n" //text2 and text3 are equal.
New jpackage
tool to package a Java application into a platform-specific package
like:
- Linux: deb and rpm
- macOS: pkg and dmg
- Windows: msi and exe
New NUMA-aware memory allocation mode, improves the G1 performance on large machines.
Add +XX:+UseNUMA
option to enable it.
14.7 JFR Event Streaming
Improved the existing JFR to support event streaming, it means now we can stream the JFR events in real-time, without the need to dump the recorded events to disk and parse it manually.
The JDK Flight Recorder (JFR) is a tool for collecting diagnostic and profiling data about a running Java application. Normally, we start a recording, stop it, dump the recorded events to disk for parsing, it works well for profiling, analysis, or debugging.
14.8 Remove the Concurrent Mark Sweep (CMS) Garbage Collector
Java 9 JEP 291 deprecated this Concurrent Mark Sweep (CMS) Garbage Collector, and now it is officially removed.
/usr/lib/jvm/jdk-14/bin/java -XX:+UseConcMarkSweepGC Test
OpenJDK 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; support was removed in 14.0