JEP 359 Preview Language Feature Hero
December 12, 2019

JEP 359: Records Preview for Java 14

Java Updates
Java Application Development

The JEP 359: Records preview language feature proposes an easier, clearer way to write data aggregate classes in Java. JEP 359: Records was announced as a preview feature for Java 14 on December 5th, 2019.

In this article, we’ll look at the reasoning behind the preview language feature, how it works, and offer some parting commentary on the path forward for this boilerplate-averse preview language feature.

Why Introduce the JEP 359: Records Preview Language Feature?

As Brian Goetz said in his November Java Language Futures presentation at Devoxx Belgium, “languages must evolve, or they risk becoming irrelevant.” But evolution for the wrong reasons can hasten that path to irrelevance. With preview language features, Java language architects can make changes to the language without that inherent risk.

In fact, preview language features can undergo several preview versions (e.g., switch expressions) before becoming adopted or abandoned in lieu of better solutions (e.g., raw string literals becoming text blocks).

For JEP 359: Records, the preview language feature was designed to chip away at a common complaint for Java — verbosity. Specifically, it targets one specific case of verbosity in Java, data aggregate classes.

Is Java Too Verbose?

It’s a valid question, especially when you consider the number of classes that serve only to aggregate or carry data, and it’s the one at the center of the JEP 359 records preview language feature

With the use of IDEs, developers often don’t have to deal with writing the code for data carrier classes. But when it comes time to dissect legacy code, (or understand your own code) these classes don’t help you to quickly or fully understand the purpose of the code.

Verbosity in Java data classes isn’t a new complaint. In fact, Kotlin, known for its syntactical concision, has already introduced a way to handle shallow data classes. Java with Lombok, a java compiler plugin that helps eliminate boilerplate code, provides an alternative route for concision.

Java 14 with records:

record User(String name, int age) {}

 

Kotlin:

data class User(val name: String, val age: Int)

 

Java, with Lombok:

@lombok.Data
class User {
  String name;
  int age;
}

 

A Boilerplate Issue

As Brian Goetz discussed in an exploratory article on Data Classes and Sealed Types for Java, developers who want to create data carrier classes in a way that are easy to understand have to write a lot of low-value and repetitive code.

This leaves many developers letting IDEs do the leg work of writing the boilerplate, but not considering much beyond functionality of the code itself.

But, when it comes time to troubleshoot that code, reading those lengthy and repetitive sections of boilerplate code that the developer didn’t directly write can be a nightmare.

public class User {
  private final String name;
  private final int age;
​
  public User(String name, int age) {
    this.name = name;
    this.age = age;
  }
​
  public String getName() {
    return name;
  }
​
  public int getAge() {
    return age;
  }
​
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    User user = (User) o;
    return age == user.age && Objects.equals(name, user.name);
  }
​
  @Override
  public int hashCode() {
    return Objects.hash(name, age);
  }
}

 

The Goal of the JEP 359: Records Preview Feature

As Brian Goetz discusses in the JEP 359: Records preview, the goal of records is to “provide a compact syntax for declaring classes which are transparent holders for shallowly immutable data.”

In his words, “it should be easy, clear and concise to declare shallowly-immutable, well-behaved nominal data aggregates.”

Mechanically Deriving APIs, Semantics of Equality and Hash Code

Aside from the direct user syntactical improvements, JEP 359 also provides a clearer way for APIs, compilers and frameworks to understand and process high level data.

By clearly and simply defining data aggregates classes, users can mechanically derive APIs, including construction APIs, deconstruction APIs (which will work with Pattern Matching), and access APIs, while allowing compilers and frameworks to make assumptions about those classes.

Restrictions and Explicit Declarations

Record classes are immutable by default, meaning all properties are final. In cases using property types that are inherently mutable, for instance an array, explicitly declaring the accessor method for the property is a way to ensure immutability. For instance by making and returning a defensive copy of an array or wrapping a List with Collections.unmodifiableList.

record Foo(String[] array) {}

vs

record Foo(String[] array) {
  public String[] array() {
    return array.clone();
  }
}

 

Final Thoughts

The JEP 359: Records preview language feature addresses a common issue with using classes as wrappers for data. It aims to make writing shallow data classes both easier, and easier to parse for developers.

While the full extent of how records will interact with APIs, compilers and frameworks is yet to be seen, the primary, the syntactical improvements alone make JEP 359 a good potential revision to the Java language.

Additional Resources

Looking for additional reading on Java preview language features? Be sure to read our recent articles:

Watch the Switch Expressions and Text Blocks Webinar

If you’re not in the reading mood, I recently recorded a webinar on switch expressions and text blocks. You can watch it by clicking the link below.

Watch the Webinar