Friends of OpenJDK Today

Avoid Multithreading Bugs Using Immutable Java 16 Records

June 07, 2021

Author(s)

  • Avatar photo
    Vipin Sharma

    I help professional Java developers to learn language features so they can work on the best Java projects, software developer, speaker, OpenJDK contributor.

In a multi-threaded Java application, any thread can change the state of an object. The Java memory model in Java language specification specifies when exactly updates made by one thread are going to be visible to other threads. This is one of the biggest problems professional Java developers deal with every day. Java records are immutable, an object is considered immutable if its state cannot change after it is constructed. The immutable nature of the record eliminates problems of its usage in a multithreaded environment.

Previous article on records explains how records provide a way to create data carrier-classes without writing a lot of boilerplate code. As part of this article, we will focus on the immutable feature of records. Immutability is one of the best features provided by records, we can use a record object without worrying about other threads changing its state.

Java language features making record immutable

In this section, we will go through a table explaining how records are made immutable in the Java language. In the below table the 2nd column explains different ways to update the state of a record object, the 3rd column explains Java language features that prevent updating the state of the Record object.

Index Way to update record Java language features preventing it
1 Create a record sub-class and change the state of the sub-class. Record classes are implicitly final and can not be abstract, this way we can not create a sub-class of the record class.
2 Extend some other class(superclass) and change the state of the superclass. All record classes extend java.lang.Record by default so can not extend any other class.
3 Add instance fields that can be modified. Record classes cannot declare instance fields.
4 Update record components. We can not assign a new value to record components as these are implicitly final. These are assigned values while initializing the record in a canonical constructor.
5 Update record components in the constructor. Only canonical constructor can update record components, which is called while initializing record. For other types of constructors, assigning any of the record components in the constructor body results in a compile-time error.
6 Update record components using reflection. Record components have specific handling in Reflection Field API. This treatment is like hidden classes. You can read more about Hidden classes here.

Shallowly immutable

Record components are final, which means we can not change the record components once assigned. Although we can change fields of the record component, there is no restriction on that, it makes the record shallowly immutable. Let's see this with an example.

public class EmployeeTest {

    public static void main(String[] args) {

        List<Integer> integerList = new ArrayList<>();
        integerList.add(1);
        IntegerListRecord integerListRecord = new IntegerListRecord(integerList);
        System.out.println(integerListRecord.getListSize());

        integerList.add(2);
        System.out.println(integerListRecord.getListSize());

    }

}

record IntegerListRecord(List<Integer> integerList) {
    int getListSize() {
        return integerList.size();
    }
}

In this example, we created a list of integers(integerList), added one element into it, and initialized the record class with this. Calling method getListSize of record class results into 1. Now we add one more element in integerList and calling getListSize results into 2. Here we did not change the record component (integerList) but updated the fields of the record component, which does not have any restriction. This is the reason we call the record shallowly immutable.

Conclusion

Records help you remove repetitive and error-prone code, and increases developer productivity. The immutability feature keeps it away from concurrency bugs. Using language features like this is going to make you a great developer everyone will want to hire.

If you want to get amazing Java jobs, I wrote an ebook 5 steps to Best Java Jobs. You can download this step-by-step guide for free!

Resources

  1. JEP 395
  2. https://cr.openjdk.java.net/~briangoetz/amber/datum.html
  3. Java language specification: Java memory model
  4. Reflection Field API Javadoc.
Topics:

Author(s)

  • Avatar photo
    Vipin Sharma

    I help professional Java developers to learn language features so they can work on the best Java projects, software developer, speaker, OpenJDK contributor.

Comments (0)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

Save my name, email, and website in this browser for the next time I comment.

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard