Java programmer expert
Java has often been criticized in the past for the amount of code that must be written to get a program to do something. The biggest complaints were directed at the data classes. Oracle was aware of this and began working to make Java acquire the attributes of brevity and developer friendliness in addition to robustness and verbosity. In Java 14[JEP-359], the authors provided a preview of how such data classes could be implemented, and after incorporating feedback from the Java community, they brought out a new extension to the Java language in Java 16[JEP-395], Java Records.

V článku sa dozvieš:
Podobne ako Enum, Record je tiež špeciálny typ triedy v Jave. Records (záznamy) sú určené na zjednodušenie vytvárania nemenných dátových objektov, často označovaných aj ako dátové nosiče. Hlavný rozdiel medzi klasickou triedou a záznamom je v tom, že záznam sa snaží odstrániť celý sprievodný kód, ktorý je potrebný napísať pri nastavení dát alebo pri ich získavaní v inštancii triedy. Java záznam túto zodpovednosť deleguje na Java kompilátor, ktorý automaticky poskytuje stručné implementácie bežných metód ako sú: konštruktor, prístup k členom triedy (getter metódy), hashCode(), equals() a toString() metóda.
In a nutshell, this important functionality of Java records has brought the ability to define immutable data more concisely, while helping to reduce the amount of repetitive code, so developers can focus mainly on programming business logic.
The best way to understand the benefits of this enhancement is by example. Let’s now look together at how we would define a data aggregate without and with Java Record. Let’s create a simple data class Book, with attributes title and price.
In this example, even though the Book class contains only two fields (name and price), a lot of repetitive code (constructor, getters, toString(), equals(), and hashCode()) needs to be written to ensure that the object works properly.
import java.util.Objects;
public class Book {
private final String name;
private final double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
@Override
public String toString() {
return "Book {name = '" + name + "', price = " + price + "}";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Book book = (Book) o;
return Double.compare(book.price, price) == 0 && name.equals(book.name);
}
@Override
public int hashCode() {
return Objects.hash(name, price);
}
}
With the introduction of the record keyword, the same data class can be defined much more concisely.
public record Book(String name, double price) {}
This one-line declaration does essentially the following:
If we look at the byte-code we can notice a few details:

The usage in the Main class is similar to what we are used to from using classic JavaBean classes. However, we have to unlearn the use of getter methods, since the record class does not contain them.
public class Main {
public static void main(String[] args) {
Book book1 = new Book("Effective Java", 47.38);
System.out.println(book1.name());
System.out.println(book1.price());
System.out.println(book1);
Book book2 = new Book("Effective Java", 47.38);
System.out.println(book1.equals(book2));
}
}
The output of this program is as follows:

In the previous example, we saw how by defining a record class using a single line, we were able to easily implement a simple data class. So let’s summarize the benefits of using Java Records.
In general, we can use records in any situation where we need to declare a simple data container with record immutability properties and want to use automatically generated methods. We will mention a few usage scenarios where Java records come in handy:
We can use records to declare simple data transfer objects that contain data. This is useful when transferring data between different layers of an application, such as between the service layer and the database layer.
Entries can be used to declare configuration objects that contain a set of configuration properties for an application or module. These objects typically have immutable properties, making them thread-safe.
When creating a REST API, it is common to return data in JSON or XML form. In such cases, we want to define a simple data structure that represents the API response. Records are ideal for this, as they allow you to define a lightweight and immutable data structure that can be easily serialized into JSON or XML.
When writing unit tests, it is often necessary to create test data for a specific test scenario. In such cases, records are ideal for this because test data is usually static and we can create more complex test suites with a minimal amount of code.
Despite their advantages, records do not fully replace the original JavaBean classes. Therefore, if we need:
Java records provide us with an elegant way to model immutable data classes with a minimum of code. It is particularly ideal for classes that are primarily used to store data, allowing developers to write cleaner and more maintainable code. By using records, we delegate the amount of code that needs to be written to the compiler. However, for scenarios involving mutable data or complex behavior, we still have traditional classes, which remain a preferable choice in such cases.
Related articles