JDK 14 was made Generally Available (GA) on 2020/03/17, bringing with it 16 new JDK Enhancement Proposals (JEPs). Coming 6 months after the release of JDK 13, it continues the JDK Project’s push for a strict, 6-month release cadence rather than the 2-year cadence it followed in the past. This faster cadence was initially proposed by Mark Reinhold as a means of progressing Java faster in a more consistent manner, as well as avoiding abnormally long delays that had plagued prior releases.
Why should one care about new JDK releases, though? As most Java developers are acutely aware, most of the industry is still dominated by JDK 8, so the likelihood of being able to use these new features in the near feature is probably low. However, as the industry gradually shifts from JDK 8 to the latest LTS release and becomes more accustomed to the new, 6-month release cadence, we should start seeing faster adoption rates of new releases.
As a result, the need to continually sharpen your sword and stay up to date will increase. Also, if you are wanting to help kickstart the shift beyond JDK 8 in your projects, knowing what value later versions bring and being able to incorporate them into your proposal can be extremely helpful in making your goal of using a newer version a reality. Besides those two reasons, it is also just plain exciting to see what the latest and greatest is and where the language is heading.
So without further ado, let’s take a look at three of the more significant enhancements that come with JDK 14: Records
, NullPointExceptions
, and instanceof
. If you like, you can check out the full list here. We’ll also briefly discuss JDK 15 and its promised JEPs.
Records
Data carrier classes in Java have always suffered from being too verbose and requiring too much ceremony to implement. IDEs have helped mitigate this by generating the constructors
, accessors
, toString()
, equals()
, and hashCode()
. This still ends up being a lot of boilerplate code that can quickly lead to defects. Records
help alleviate this problem by reducing the boilerplate and allowing the user to actually model their data as data.
Basically, a record
is an immutable, transparent data carrier for a fixed set of fields. Consider the following example.
record Point(int x, int y) { }
This record
consists of a name (Point
) and a state description (int x, int y
) which declares the components of the record
.
With a record
, you get the following standard members automatically.
- A private final field for each component of the state description
- A public read accessor method for each component of the state description with the same name and type as the component
- A public constructor whose signature is the same as the state description, which initializes each field from the corresponding argument
- Implementations of equals and
hashCode
that say two records are equal if they are of the same type and contain the same state - An implementation of
toString
that includes the string representation of all the record components with their names
Pretty awesome, huh? At this point, you may be wondering if you can declare your own methods, fields, etc. in the body of a record
. The short answer to this is yes, but do so with caution and intent. The goal of a record
is to be a simple, shallow data carrier, so by adding more to it, if you’re not careful, you can undermine its simplicity and make it complicated.
One last cool thing to note about records is that you can define a constructor for validation or normalization of its parameters without a formal parameter list, as it is assumed to align with the state description.
record Point(int x, int y) { public Point { if (x < 0) { throw new IllegalArgumentException( "x must be >= 0"); } } }
Helpful NullPointerExceptions
NullPointerExceptions
arise when you attempt to use a reference to an object that has not yet been initialized. The error message generated is usually enough to figure out what the culprit is based on the line number, but not when you have multiple references on the same line or chained references. Consider the following example:
a.b.c.d = 1; Exception in thread "main" java.lang.NullPointerException at Example.main(Example.java:42)
Based on the error message, it is not immediately clear which object reference has resulted in the NullPointerException
, as we are only given the line number to work with. With JEP 358 however, the error message will make it clearer as to the cause of the NullPointerException
, as seen below.
Exception in thread "main" java.lang.NullPointerException: Cannot read field "c" because "b" is null at Example.main(Example.java:42)
Pattern Matching instanceof
Sometimes, you find yourself in a circumstance where you just don’t know what the exact type of an object is when you need to. To aide in times like this, Java provides you with the instanceof
operator to help determine an object type.
Object o = "world"; if (o instanceof String) { String s = (String)o; System.out.println("hello " + s); }
As you can see, this first requires you to explicitly cast the object before using it as that type. With JEP 305, the instanceof
operator has been extended to allow a variable to be specified and implicitly cast to the type.
Object o = "world"; if (o instanceof String s) { System.out.println("hello " + s); }
JDK 15
As of now, JDK 15 is scheduled to be GA on 2020/09/15. It has 5 JEPs targeted so far.
- JEP 371: Hidden Classes – These are classes that cannot be used directly by the bytecode of other classes. The purpose of hidden classes is to be used by frameworks that generate classes at runtime and then to be used indirectly with reflection.
- JEP 372: Remove the Nashorn Javascript Engine – This JEP would fully remove the Nashorn Javascript Engine, APIs, and jjs tool. This was previously deprecated back in JDK 11 with JEP 335.
- JEP 377: ZGC – A Scalable, Low-Latency Garbage Collector that was introduced in JDK 11. This JEP would make the Z garbage collector to a production feature.
- JEP 378: Text Blocks – First introduced in JDK 13 with JEP 355 and previewed for a second time in JDK 14 with JEP 368, this JEP proposes making text blocks a standard feature.
- JEP 379: Shenandoah – A Low-Pause-Time Garbage Collector that was first integrated into JDK 12 with JEP 189. This JEP proposes making the GC a production feature.
Conclusion
JDK 14 has brought a multitude of new and exciting features that further enhance the language and overall developer experience. While we are still several months out, JDK 15 is shaping up to be quite good as well.
I look forward to seeing what the future holds for Java – now available in frequent, bite-sized chunks of goodness.