{"id":7917,"date":"2024-10-18T16:13:04","date_gmt":"2024-10-18T16:13:04","guid":{"rendered":"https:\/\/msgprogramator.sk\/?p=7917"},"modified":"2026-04-01T11:59:19","modified_gmt":"2026-04-01T11:59:19","slug":"java-records","status":"publish","type":"post","link":"https:\/\/msgprogramator.sk\/en\/java-records\/","title":{"rendered":"Java records &#8211; an efficient way to manage data classes in modern programming"},"content":{"rendered":"<p>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<a href=\"https:\/\/openjdk.org\/jeps\/359\" target=\"_blank\" rel=\"nofollow noopener\">[JEP-359<\/a>], 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<a href=\"https:\/\/openjdk.org\/jeps\/395\" target=\"_blank\" rel=\"nofollow noopener\">[JEP-395<\/a>], <strong>Java Records<\/strong>.<\/p>\n<h2>What is Java Record?<\/h2>\n<p>Podobne ako Enum, <strong>Record<\/strong> je tie\u017e \u0161peci\u00e1lny typ triedy v Jave. Records (z\u00e1znamy) s\u00fa ur\u010den\u00e9 na zjednodu\u0161enie vytv\u00e1rania nemenn\u00fdch d\u00e1tov\u00fdch objektov, \u010dasto ozna\u010dovan\u00fdch aj ako d\u00e1tov\u00e9 nosi\u010de. Hlavn\u00fd rozdiel medzi klasickou triedou a z\u00e1znamom je v tom, \u017ee z\u00e1znam sa sna\u017e\u00ed odstr\u00e1ni\u0165 cel\u00fd sprievodn\u00fd k\u00f3d, ktor\u00fd je potrebn\u00fd nap\u00edsa\u0165 pri nastaven\u00ed d\u00e1t alebo pri ich z\u00edskavan\u00ed v in\u0161tancii triedy. Java z\u00e1znam t\u00fato zodpovednos\u0165 deleguje na Java kompil\u00e1tor, ktor\u00fd automaticky poskytuje stru\u010dn\u00e9 implement\u00e1cie be\u017en\u00fdch met\u00f3d ako s\u00fa: kon\u0161truktor, pr\u00edstup k \u010dlenom triedy (getter met\u00f3dy), <em>hashCode()<\/em>, <em>equals()<\/em> a <em>toString()<\/em> met\u00f3da.<\/p>\n<p>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.<\/p>\n<p>The best way to understand the benefits of this enhancement is by example. Let&#8217;s now look together at how we would define a data aggregate without and with Java Record. Let&#8217;s create a simple data class Book, with attributes title and price.<\/p>\n<h2>Example: data class Book without using Record<\/h2>\n<p>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.<\/p>\n<pre><code class=\"language-java\" data-line=\"\">import java.util.Objects;\n\npublic class Book {\n    private final String name;\n    private final double price;\n\n    public Book(String name, double price) {\n        this.name = name;\n        this.price = price;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public double getPrice() {\n        return price;\n    }\n\n    @Override\n    public String toString() {\n        return &quot;Book {name = &#039;&quot; + name + &quot;&#039;, price = &quot; + price + &quot;}&quot;;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n        Book book = (Book) o;\n        return Double.compare(book.price, price) == 0 &amp;&amp; name.equals(book.name);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name, price);\n    }\n}<\/code><\/pre>\n<h2>Example: data class Book using Record<\/h2>\n<p>With the introduction of the <strong>record<\/strong> keyword, the same data class can be defined much more concisely.<\/p>\n<pre><code class=\"language-java\" data-line=\"\">public record Book(String name, double price) {}<\/code><\/pre>\n<p>This one-line declaration does essentially the following:<\/p>\n<ul>\n<li>defines a Book class with two final attributes: name and price,<\/li>\n<li>automatically generates the constructor, getter methods, toString(), equals(), and hashCode() .<\/li>\n<\/ul>\n<p>If we look at the byte-code we can notice a few details:<\/p>\n<ul>\n<li>The compiler replaced the <strong>record<\/strong> keyword with the word <strong>class<\/strong>.<\/li>\n<li>The compiler declared the class as <strong>final<\/strong>. This means that this class cannot be extended. It also means that it cannot be inherited and is immutable by nature.<\/li>\n<li>The converted class inherits from <em>lang.Record<\/em>. All records are a subclass of the Record class defined in the <em>java.lang<\/em>.<\/li>\n<li>There is a parameterized constructor added by the compiler.<\/li>\n<li>The compiler automatically generated the <em>toString()<\/em>, <em>hashCode()<\/em> and <em>equal()<\/em> methods.<\/li>\n<li>The compiler has added methods to access class attributes. They match the attribute names and do not contain any prefixes such as get or set.<\/li>\n<\/ul>\n<figure id=\"attachment_4622\" aria-describedby=\"caption-attachment-4622\" style=\"width: 1200px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-4621 size-full\" src=\"https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/trieda_book_vytvorena_kompilatorom_zo_zaznamu.webp\" alt=\"Book class created by the compiler from a record\" width=\"1200\" height=\"401\" srcset=\"https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/trieda_book_vytvorena_kompilatorom_zo_zaznamu.webp 1200w, https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/trieda_book_vytvorena_kompilatorom_zo_zaznamu-300x100.webp 300w, https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/trieda_book_vytvorena_kompilatorom_zo_zaznamu-1024x342.webp 1024w, https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/trieda_book_vytvorena_kompilatorom_zo_zaznamu-768x257.webp 768w\" sizes=\"auto, (max-width: 1200px) 100vw, 1200px\" \/><figcaption id=\"caption-attachment-4622\" class=\"wp-caption-text\">Book class created by the compiler from a record<\/figcaption><\/figure>\n<p>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 <strong>record<\/strong> class does not contain them.<\/p>\n<pre><code class=\"language-java\" data-line=\"\">public class Main {\n    public static void main(String[] args) {\n        Book book1 = new Book(&quot;Effective Java&quot;, 47.38);\n        System.out.println(book1.name());\n        System.out.println(book1.price());\n        System.out.println(book1);\n        Book book2 = new Book(&quot;Effective Java&quot;, 47.38);\n        System.out.println(book1.equals(book2));\n    }\n}<\/code><\/pre>\n<p>The output of this program is as follows:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-4630 size-large\" src=\"https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/vystup_triedy_book_record-1024x514.webp\" alt=\"Program output - Book data class using Record\" width=\"640\" height=\"321\" srcset=\"https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/vystup_triedy_book_record-1024x514.webp 1024w, https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/vystup_triedy_book_record-300x151.webp 300w, https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/vystup_triedy_book_record-768x385.webp 768w, https:\/\/msgprogramator.sk\/wp-content\/uploads\/2024\/10\/vystup_triedy_book_record.webp 1200w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/p>\n<h2>Benefits of using Java Records<\/h2>\n<p>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&#8217;s summarize the benefits of using Java Records.<\/p>\n<ol>\n<li><strong>Reducing the amount of code<\/strong>: As has been shown, the use of records eliminates the need to manually write many of the accompanying but necessary methods. These methods have not disappeared, the compiler handles them.<\/li>\n<li><strong>Immutability<\/strong>: records are immutable by design. Once an object is created, its fields cannot be changed. This makes records ideal for scenarios where immutability is a requirement (e.g., domain entities in functional programming or distributed systems).<\/li>\n<li><strong>Automated access methods<\/strong>: records automatically generate access methods (getters) for each field. Instead of the typical getFieldName(), however, these methods have the same names as the attributes. For example, in Record Book, we use the book.name() and book.price() methods to access the data.<\/li>\n<li><strong>Built-in canonical constructor<\/strong>: when record is defined, a canonical constructor is automatically created that initializes all fields in the record.<\/li>\n<li><strong>Easy extension with new attributes<\/strong>: changes in the logic do not require updating the standard methods, which are generated automatically and correctly by the compiler. The new attributes are taken care of by the compiler, which pregenerates the code and creates a new class.<\/li>\n<li><strong>Error reduction<\/strong>: the common errors that used to occur, for example, when defining the <em>equals()<\/em> method, that is, defining the logic when two object instances are the same, are a thing of the past. The correctness of the code automatically generated by the compiler can be relied upon.<\/li>\n<\/ol>\n<h2>When to use Java Records<\/h2>\n<p>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:<\/p>\n<h3>Data transfer objects (DTOs)<\/h3>\n<p>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.<\/p>\n<h3>Configuration objects<\/h3>\n<p>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.<\/p>\n<h3>Web service answers<\/h3>\n<p>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.<\/p>\n<h3>Test data<\/h3>\n<p>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.<\/p>\n<h2>When to avoid using Java Records<\/h2>\n<p>Despite their advantages, records do not fully replace the original JavaBean classes. Therefore, if we need:<\/p>\n<ul>\n<li><strong>Changing data after creation<\/strong><br \/>\nIf the data needs to be changed after creation, you will need to delete the old instance and create a new instance of the class or use a standard class instead of the record class.<\/li>\n<li><strong>Comprehensive business logic<\/strong><br \/>\nAlthough Java record can contain methods with business logic, it is recommended to maintain records as data entities where possible and implement the business logic in separate classes that then work with the records. However, if your class requires complex logic beyond data storage, traditional classes will be a better choice.<\/li>\n<\/ul>\n<h2>Conclusion<\/h2>\n<p>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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Read about Java records, a special class that allows you to define immutable data more concisely, with example Java code.<\/p>\n","protected":false},"author":14,"featured_media":4628,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[57],"tags":[],"class_list":["post-7917","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/posts\/7917","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/users\/14"}],"replies":[{"embeddable":true,"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/comments?post=7917"}],"version-history":[{"count":2,"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/posts\/7917\/revisions"}],"predecessor-version":[{"id":42916,"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/posts\/7917\/revisions\/42916"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/media\/4628"}],"wp:attachment":[{"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/media?parent=7917"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/categories?post=7917"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/msgprogramator.sk\/en\/wp-json\/wp\/v2\/tags?post=7917"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}