DEV Community

Cover image for Introducing Java 14 Records
Lemuel Ogbunude
Lemuel Ogbunude

Posted on

Introducing Java 14 Records

There are a couple of nice features coming with the JDK 14 release, for now, we would just have a look at Records.

The six-month release cadence set for Java seems to be working and I think it was a great move by the team.

We shouldn't expect "cool" features with every release and should understand that the features added to Java are not to make it "shinny" or "cool" but rather to boost developer productivity and reduce bugs.

Consider the Java code below:

    public static void main(String[] args) {

        var json = """
                {
                "statusCode" : 404,
                "statusMessage" : "Not Found"
                }
                """;

        var gson = new Gson();

        //var message = gson.fromJson(json, );

    }

All we need is a Java class to be used while deserialising the JSON string. It's a class to just hold some data.

We might have to write something that looks like this:

public class Response {
    private final int statusCode;
    private final String statusMessage;

    public Response(int statusCode, String statusMessage) {
        this.statusCode = statusCode;
        this.statusMessage = statusMessage;
    }

    public int getStatusCode() {
        return statusCode;
    }

    public String getStatusMessage() {
        return statusMessage;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Response response = (Response) o;

        if (getStatusCode() != response.getStatusCode()) return false;
        return getStatusMessage() != null ? getStatusMessage().equals(response.getStatusMessage()) : response.getStatusMessage() == null;
    }

    @Override
    public int hashCode() {
        int result = getStatusCode();
        result = 31 * result + (getStatusMessage() != null ? getStatusMessage().hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "Response{" +
                "statusCode=" + statusCode +
                ", statusMessage='" + statusMessage + '\'' +
                '}';
    }
}

Now we can use this class with our Gson library:

    public static void main(String[] args) {

        var json = """
                {
                "statusCode" : 404,
                "statusMessage" : "Not Found"
                }
                """;

        var gson = new Gson();

        var message = gson.fromJson(json, Response.class);

    }

While the Response class could easily be generated with our IDE, it could be an issue while reading. We shouldn't have to read through over 40 lines just to find out this class was built to simply hold data.

We could replace all that code in the Response class by using a Record:

public record Response(int statusCode, String statusMessage) {

}

A Record would automatically generate a constructor whose signature matches the state description, private final fields and getter methods for each state component.

Yes, the fields are final, a Record cannot extend other classes and a Record itself is final. You should begin to realise that Records are not here to replace mutable JavaBean classes.

Records also generate implementations of the methods equals(), hashCode(), and toString(). You, however, are still free to override those methods if you wish.

Records are useful in situations where we need to model plain data.

We can create Records in methods just like in the case of normal classes. This makes sense if we are only going to make use of the Record in that particular method:

    public static void main(String[] args) {
        record Response(int statusCode, String statusMessage) {

        }

        var json = """
                {
                "statusCode" : 404,
                "statusMessage" : "Not Found"
                }
                """;

        var gson = new Gson();

        var message = gson.fromJson(json, Response.class);

    }

Let's say you want to set some values in the constructor if the status code is 200, you have the option of working with the common canonical constructor:

public record Response(int statusCode, String statusMessage) {
    public Response(int statusCode, String statusMessage) {
        this.statusCode = statusCode;
        this.statusMessage = statusMessage;

        if(statusCode==200){
            //extra code here
        }
    }
}

The issue here is that we have to repeat the code that was already derivable from the state description. To avoid this we can use the compact version of the constructor:

public record Response(int statusCode, String statusMessage) {
    public Response {
        if (statusCode == 200) {
            //extra code here
        }
    }
}

With the compact version, we can focus on reading the extra code and not get distracted by boilerplate already generated by Records.

Summary

Records are one of the many nice features coming to Java and the six-month release cadence helps us access these features faster.

Newer programming languages are like young sportsmen who can afford to try new shiny stunts, get injured and heal quickly, whereas languages like Java are like more experienced athletes who have to avoid injury and make sure no move breaks anything.

So while there are many features you would love to see in Java, the priority of backward compatibility and avoiding a design mistake would affect what features are added and when they are added.

For the record 😉, JDK 14 is not an LTS release and Records would be a preview feature in JDK 14.

Records can be used in a wide variety of situations, I have just scratched the surface, I suggest you go through the articles below:

"Java 14 Feature Spotlight: Records" by Brian Goetz

JEP 359: Records (Preview)

Top comments (5)

Collapse
 
leob profile image
leob • Edited

Nice to see that Java (which I would respectfully call "the COBOL of the 21st century" because of the huge amount of mission critical systems developed in it) isn't stuck in the past and is still evolving. Looking at this piece of Java code with "var" and "record" it's definitely a step up from your dad's Java.

Collapse
 
fdrobidoux profile image
Félix Dion-Robidoux

Wow, I didn't know about the new release methods they established for new Java releases. Looks like they're going the C# route, and I'm really happy about that.

Maybe I shouldn't have shivers down my spines anymore when I'm told about a job opportunity in Java if this momentum keeps up.

Collapse
 
lemuelogbunude profile image
Lemuel Ogbunude

Yeah the new Java release method is nice :)

Collapse
 
danondso profile image
Dublin Anondson

Interesting. It looks like they're trying to do Lombok without the Lombok.

Collapse
 
brunooliveira profile image
Bruno Oliveira

Perfection!!!