Java 16 introduced JEP 395: Records as an incubated feature, and with Java 17, this feature was standardized. Records provide a new way to model immutable data structures with less boilerplate code. They are a special type of class designed to hold data without needing the user to write code for typical methods such as constructors, getters, equals()
, hashCode()
, and toString()
.
The main goal of Records is to simplify code by automatically providing the standard functionality required for simple data-carrying classes, such as value objects or data transfer objects (DTOs).
What Are Records?
A Record in Java is a special kind of class that primarily focuses on storing immutable data. It is designed to reduce the verbosity of creating simple POJOs (Plain Old Java Objects).
Before records, developers had to manually write the following for a simple data object:
- A constructor to initialize the fields.
- Getter methods to access the fields.
equals()
andhashCode()
methods to compare instances.toString()
method to provide a string representation of the object.
With records, Java automatically generates all of these methods for you.
Syntax of Records
A record is defined using the record
keyword:
public record Person(String name, int age) { }
Code language: JavaScript (javascript)
In the above example:
Person
is a record with two fields:name
(aString
) andage
(anint
).- Java automatically provides a constructor, getters,
equals()
,hashCode()
, andtoString()
methods.
You can also define additional methods and customize some behavior within the record if needed.
public class Person {
private final String name;
private final int age;
public Person(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 obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
Code language: PHP (php)
Java 17 Record:
<strong>public record Person(String name, int age) { }</strong>
Code language: HTML, XML (xml)
Notice how the record definition is significantly more concise, with no need to write getters, constructors, equals()
, hashCode()
, or toString()
. Java automatically provides these methods when the record is compiled.
Additional Capabilities
While records are designed for simplicity, they still offer flexibility and can be extended in the following ways:
-
Custom Methods: You can define custom methods within a record to implement specific behavior.
public record Person(String name, int age) {
public String greet() {
return "Hello, my name is " + name;
}
}
Code language: JavaScript (javascript)
   2.Custom Constructors: You can also define a custom constructor if you need some additional logic when creating the
    record instance.
public record Person(String name, int age) {
public Person {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
}
}
Code language: PHP (php)
 3.  Implements Interfaces: Records can implement interfaces just like regular classes.
public record Person(String name, int age) implements Comparable<Person> {
@Override
public int compareTo(Person other) {
return this.age - other.age;
}
}
Code language: JavaScript (javascript)
Benefits of Records
Benefit | Explanation |
---|---|
Less Boilerplate | Records generate methods like toString() , equals() , and hashCode() automatically, reducing repetitive code. |
Immutable | Fields in a record are final by default, which ensures immutability and thread-safety. |
Compact Syntax | A record definition is much more compact and concise compared to a traditional class. |
Pattern Matching Ready | Records are designed with future features like pattern matching in mind. This allows for simpler checks when deconstructing data types. |
Limitations of Records
- Immutability: Since fields are implicitly
final
, you cannot change them once the record is created. This can be a limitation when mutable data is needed. - No Inheritance (Extending other classes): Records cannot extend other classes, although they can implement interfaces.
- No setters: Records don’t have setters because their fields are immutable.
The standardization of JEP 395: Records in Java 17 provides developers with a simple, concise, and immutable data structure. This feature significantly reduces boilerplate code, making Java applications more maintainable, especially when dealing with data transfer objects (DTOs) or value objects. Records are a great fit for use cases where immutability is essential, and Java 17’s standardization means this feature will be available for widespread use in production applications.