Java Records With Example

Java records, introduced in Java SE 14, are a concise way to create classes specifically designed to hold data. They are similar to traditional Java classes, but with some key differences:

Reduced Boilerplate Code: Records automatically generate common methods like constructors, getters (accessors), equals(), hashCode(), and toString() based on the fields you define. This saves you time and effort writing repetitive code.

Immutability: By default, record fields are final, making the records themselves immutable. This means the data cannot be changed after the record is created. Immutability promotes thread safety and simplifies reasoning about your code.

Focus on Data: Since records handle the boilerplate methods, you can focus on the core functionality of your data class, which is storing and accessing data.

Here’s an example of a simple Java record representing a person:

record Person(String name, int age) {
  // Compiler-generated methods: getters, equals, hashCode, toString
}

In this example, the Person record has two fields: name (String) and age (int). The compiler will automatically generate the following methods:

-A constructor to initialize the name and age fields.
-Getter methods name() and age() to access the corresponding fields.
equals(), hashCode(), and toString() methods for object comparison and string representation.

Java records are a valuable addition for creating lightweight data carrier classes, especially for Plain Old Java Objects (POJOs) and Data Transfer Objects (DTOs). They improve code readability, reduce boilerplate, and promote immutability for safer applications.

can we define multiple constructors in Java records ?

Yes, we can define multiple constructors in Java records starting from Java 15 (including Java 16 and later).However, there’s a key point to remember:

Every constructor must delegate to the record’s canonical constructor.

The canonical constructor is the default constructor that initializes all the record’s fields. It can be explicitly defined by you, or the compiler will generate it automatically if not provided.

Here’s how you can define multiple constructors in a record:

1. Custom Constructor with Full Field Initialization:

You can define a constructor that initializes all the fields and explicitly calls the canonical constructor using this(…).

2.Constructor with Partial Initialization:

You can create a constructor with a subset of fields and delegate to another constructor that initializes the remaining fields. This constructor chain ultimately leads to the canonical constructor.

Here’s an example with both scenarios:

record Point(int x, int y) {
  // Explicit canonical constructor (optional)
  public Point(int x, int y) {
    this.x = x;
    this.y = y;
  }

  // Custom constructor with full initialization
  public Point(int x, int y, String label) {
    this(x, y); // Delegate to canonical constructor
    // Perform additional logic or initialization with label
  }

  // Constructor with partial initialization
  public Point(int x) {
    this(x, 0); // Delegate to constructor with both x and y
  }
}

Limitations:

You cannot have a constructor with a more restrictive access modifier than the record itself.
You cannot directly call other constructors besides the canonical one in your custom constructors.

By using multiple constructors, you can provide different ways to create record objects depending on the available data or desired initialization logic.

Java records Basic Example :

Here’s a basic example using Java records for a simple library book management system:

package records.demo;
public class Library {
  public static void main(String[] args) {
    // Define a record to represent a book
    record Book(String title, String author, int year) {
      // Compiler-generated methods (getters, equals, hashCode, toString)
    }

    // Create some book objects
    Book book1 = new Book("The Lord of the Rings", "J.R.R. Tolkien", 1954);
    Book book2 = new Book("Pride and Prejudice", "Jane Austen", 1813);

    // Access book information using getters
    System.out.println("Book Title: " + book1.title());
    System.out.println("Author: " + book1.author());
    System.out.println("Year Published: " + book1.year());

    // Check if two books are equal based on content
    if (book1.equals(book2)) {
      System.out.println("These books are the same.");
    } else {
      System.out.println("These books are different.");
    }
  }
}

Output :

Book Title: The Lord of the Rings
Author: J.R.R. Tolkien
Year Published: 1954
These books are different.

Explanation:

  1. We defined a “Library” class with a “main” method to demonstrate record usage.
  2. Inside “main”, we create a record named “Book” with three fields: “title” (String), “author” (String), and “year” (int).
  3. The compiler automatically generates methods like getters for each field (“title()”, “author()”, “year()”), “equals()“, “hashCode()“, and “toString()“.
  4. We create two “Book” objects, “book1” and “book2“, with sample data.
  5. We access book information using the generated getters (“title()”, etc.).
  6. We compare two books for equality using the “equals()” method. This checks if the content of both objects is the same.
  7. Finally, we print messages based on the book information and equality check.

This example showcases how Java records can simplify data management for basic scenarios. They provide a clean and efficient way to define data structures with minimal boilerplate code.

is Java Record Replacement for Model Class ?

No, Java records are not a complete replacement for model classes. They are designed for a specific purpose, while model classes offer more flexibility. Here’s a breakdown of the key differences:

Java Records:

  • Focus: Hold data (immutable by default)
  • Use cases: Simple data structures, DTOs (Data Transfer Objects), configuration settings
  • Benefits: Concise syntax, built-in methods (equals, hashCode, toString)
  • Drawbacks: Limited functionality, not meant for complex logic or inheritance

Model Classes:

  • Focus: Encapsulate data and behavior (can be mutable or immutable)
  • Use cases: Represent real-world entities, business objects
  • Benefits: Flexible, can define custom logic and behavior, inheritance support
  • Drawbacks: Can be more verbose compared to records

In summary:

  • Use records when you need a simple, immutable data holder.
  • Use model classes when you need an object with behavior, state changes, or inheritance.

Think of records as a lightweight option for specific data-centric tasks, while model classes are more general-purpose for building complex objects.

Ditch the Boilerplate code in Java, Records Are Java’s New Best Friend || Records In Java

Happy Learning..

Leave a Reply

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