← Back to Advanced Java Course | Chapter 4: Modern Java Features | Lesson 3 of 12

Java Records

A record is a short way to make a simple class that only holds data, like a ready-made form. Java writes the routine parts for you.
Syntax
java
record RecordName(Type component1, Type component2) { }

RecordName object = new RecordName(value1, value2);
object.component1();

Introduction to Records

A Java record is a special, compact kind of class designed specifically to act as a simple, immutable data carrier. Declaring one automatically generates private final fields, a canonical constructor, accessor methods, and correct hashCode(), equals(), and toString() implementations, all without you writing that boilerplate by hand.

Example: Introduction to Records

java
// Define the class Main
public class Main {
	// Define the record Point (an immutable data carrier)
	record Point(int x, int y) {}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Create a new Point object and store it in p
		Point p = new Point(3, 4);
		// Print a line to the console
		System.out.println(p.x() + "," + p.y() + " " + p);
	}
}

Compact Constructors

You can add a compact constructor to a record to validate or normalize its data before it's stored, without needing to redeclare the record's parameter list in that constructor's signature. This is the idiomatic place to reject invalid input, such as throwing on a negative age.

Example: Compact Constructors

java
// Define the class Main
public class Main {
	// Define the record Person (an immutable data carrier)
	record Person(String name, int age) {
		Person {
			if (age < 0) throw new IllegalArgumentException("age cannot be negative");
		}
	}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Create a new Person object and store it in p
		Person p = new Person("Anya", 25);
		// Print a line to the console
		System.out.println(p);
	}
}

Custom Methods and Fields

You can define custom instance methods, static methods, and static fields inside a record just like an ordinary class. However, you cannot declare any additional instance fields beyond the ones already listed in the record's header, since that would break its guarantee of being a simple, fixed data shape.

Example: Custom Methods and Fields

java
// Define the class Main
public class Main {
	// Define the record Circle (an immutable data carrier)
	record Circle(double radius) {
		static final double PI = 3.14159;
		double area() {
			// Send PI * radius * radius back to the caller
			return PI * radius * radius;
		}
	}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Create a new Circle object and store it in c
		Circle c = new Circle(2);
		// Print a line to the console
		System.out.println(c.area());
	}
}

Implementing Interfaces

Records are implicitly final, meaning they can never extend any other class, since allowing subclassing would undermine their immutability guarantees. They can, however, implement any number of interfaces, which is how you give a record additional behavior or contracts.

Example: Implementing Interfaces

java
// Define the class Main
public class Main {
	// Define the interface Shape
	interface Shape {
		double area();
	}
	// Define the record Square (an immutable data carrier)
	record Square(double side) implements Shape {
		public double area() { return side * side; }
	}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Create a new Square object and store it in s
		Shape s = new Square(4);
		// Print a line to the console
		System.out.println(s.area());
	}
}

Nested and Local Records

You can declare a record nested inside another class, or even locally inside a single method's scope for a quick, throwaway data shape. Local records declared inside a method are implicitly static, so they can't capture the enclosing instance.

Example: Nested and Local Records

java
public class Main {
	record Outer(int value) {
		record Inner(String label) {} // nested record
	}
	public static void main(String[] args) {
		record Local(int n) {} // local record, implicitly static
		Local l = new Local(7);
		System.out.println(l);
	}
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Trying to call a setter or change a record field, when all record components are final so a record cannot be modified after creation.
  2. Calling p.getX(), when a record's accessor is named after the component, so it is p.x().
  3. Trying to make a record extend another class or declare extra instance fields, which is not allowed because records already extend Record and only have their components.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.