Java Record Classes
July 30, 2021
This page will walk through Java record classes. Let us understand it step-by-step.
1. Java record class is a special kind of Java class that serves as a simple data carrier.
2. The record class was introduced in Java 14 as preview feature and previewed again in Java 15. The record class has been adopted as permanent language feature in Java 16 (JEP 395).
3. The record class fields are
final
and their appropriate accessors are created automatically.
4. The record class constructor,
equals
, hashCode
, and toString
methods are created automatically.
5. The record class is created using
record
keyword.
Find a sample
record
class.
record Employee(String name, int age, String city) { }
Employee
record class will accept three arguments that are 'name', 'age' and 'city'. The final
fields of Employee
record class will be of same name that are 'name', 'age' and 'city' and its accessor methods will be 'name()', 'age()' and 'city()'. All these fields and methods will be created automatically. We can use this record class in our code as following.
Employee emp = new Employee("Mahesh", 22, "Varanasi"); System.out.println(emp.name()); //Mahesh System.out.println(emp.age()); //22 System.out.println(emp.city()); //Varanasi
record
class in detail.
Contents
- 1. Creating Record Class
- 2. Creating Java Class equivalent to Record Class
- 3. Compact Constructor
- 4. Explicit Declaration of Accessors
- 5. Explicit Declaration of static Fields, static Initializers, and static Methods
- 6. Explicit Declaration of Instance Methods
- 7. Nested Record Class
- 8. Local Record Class
- 9. Additional Features of Record Classes
- 10. Creating and Importing a Custom Class with Name "Record"
- 11. References
1. Creating Record Class
A record class is created usingrecord
keyword. We are creating a record class Item
here.
record Item(int id, String name) { }
id
and name
in above record class. The Item
class will have two final
fields that are id
and name
. The accessors for Item
class will be created automatically and that are id()
and name()
methods. The constructor, equals
, hashCode
, and toString
methods will also be created automatically for Item
record class. We can instantiate our record class Item
as following.
Item item = new Item(10, "Item1");
Item
instance can be accessed by calling item.id()
and item.name()
.
Find the complete code.
MyApp.java
package com.concretepage; record Item(int id, String name) { } public class MyApp { public static void main(String[] args) { Item item = new Item(10, "Item1"); System.out.println(item.id() +", " + item.name()); } }
10, Item1
2. Creating Java Class equivalent to Record Class
A record class avoids writing lots of lines of code. Suppose we have a record class as following.record Item(int id, String name) { }
record
keyword, we need to write following boilerplate code.
Item.java
package com.concretepage; import java.util.Objects; public final class Item { private final int id; private final String name; public Item(int id, String name) { this.id = id; this.name = name; } int id() { return this.id; } String name() { return this.name; } @Override public int hashCode() { return Objects.hash(id, name); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj instanceof Item other) { return Objects.equals(id, other.id) && Objects.equals(name, other.name); } else { return false; } } @Override public String toString() { return "Item[id=" + id + ", name=" + name + "]"; } }
a. A record class is a
final
class. It means we cannot inherit a record class.
b. All the fields of record class are
final
.
c. Accessor methods of record class are named as field names.
d. The constructor,
hashCode
, equals
, and toString
methods are created by default in a record class.
3. Compact Constructor
We can declare record class with compact constructor. Compact constructor can be used to validate arguments or for some other processing.Example:
package com.concretepage; record Item (int id, String name) { public Item { if (id < 100 || name.isEmpty()) { throw new IllegalArgumentException("Invalid data"); } } } public class MyApp { public static void main(String[] args) { Item item1 = new Item(101, "Item1"); System.out.println(item1); Item item2 = new Item(50, "Item2"); System.out.println(item2); } }
Item[id=101, name=Item1] Exception in thread "main" java.lang.IllegalArgumentException: Invalid data
4. Explicit Declaration of Accessors
We can explicitly declare methods that correspond to our record class components. We need to ensure that they have the same characteristics as implicitly derived accessors, such as it should bepublic
and have same return
type as the corresponding record class component. In the same way, while implementing hashCode
, equals
, and toString
, we should ensure that they have the same characteristics and behavior as those in the java.lang.Record
class because this is the super class of all record classes.
Find the example to explicitly declare accessor method.
package com.concretepage; record Item (int id, String name) { public String name() { System.out.println("Item name: " + name); return name; } } public class MyApp { public static void main(String[] args) { Item item = new Item(101, "Item1"); System.out.println(item.name()); } }
Item name: Item1 Item1
5. Explicit Declaration of static Fields, static Initializers, and static Methods
We can declare static fields, static initializers, and static methods in a record class and they behave in the same way as in normal class. Find the sample example.package com.concretepage; record Team(int id, String name, String tech) { static String javaTech; static String angularTech; static { javaTech = "Java"; angularTech = "Angular"; } public static Team createJavaTeam(int id, String name) { return new Team(id, name, javaTech); } public static Team createAngularTeam(int id, String name) { return new Team(id, name, angularTech); } } public class MyApp { public static void main(String[] args) { Team team1 = Team.createJavaTeam(101, "Team A"); System.out.println(team1); Team team2 = Team.createAngularTeam(201, "Team B"); System.out.println(team2); } }
Team[id=101, name=Team A, tech=Java] Team[id=201, name=Team B, tech=Angular]
6. Explicit Declaration of Instance Methods
We can declare explicit instance methods in a record class but we cannot declare instance variables (non-static fields) or instance initializers in a record class.Find the example to declare an instance method in a record class.
package com.concretepage; record Rectangle(int length, int width) { public int getArea() { return length * width; } } public class MyApp { public static void main(String[] args) { Rectangle r = new Rectangle(10, 5); int area = r.getArea(); System.out.println(area); } }
7. Nested Record Class
We can declare nested record classes within a record class. Nested record classes are implicitly static.package com.concretepage; record Rectangle(int length, int width) { record BigRectangle(int num) { public BigRectangle { num = num * 2; } } public Rectangle createBigRectangle(int num) { BigRectangle b = new BigRectangle(num); int l = length + b.num(); int w = width + b.num(); return new Rectangle(l, w); } } public class MyApp { public static void main(String[] args) { Rectangle r = new Rectangle(10, 5); Rectangle br = r.createBigRectangle(3); System.out.println(br); } }
Rectangle[length=16, width=11]
8. Local Record Class
We can create local record class within the body of a method similar to a local class. Find the example.package com.concretepage; public class MyApp { public static void main(String[] args) { record Item(int id, String name) {} Item item = new Item(10, "Item1"); System.out.println(item); MyApp ob = new MyApp(); int area = ob.calculateArea(5); System.out.println(area); } int calculateArea(int size) { record Rectangle(int length, int width) {} Rectangle r = new Rectangle(size * 2, size); return r.length() * r.width(); } }
Item[id=10, name=Item1] 50
9. Additional Features of Record Classes
1. We can create a generic record class.record Rectangle<C extends Shape> (C length, C width) { }
record Employee(int id, String name) implements Person { }
record Rectangle( @GreaterThanZero int length, @GreaterThanZero int width) { }
5. We can serialize and deserialize instances of record classes but we cannot customize its process by using
writeObject
, readObject
, readObjectNoData
, writeExternal
, or readExternal
methods.
6. In Java 16, the
java.lang.Class
introduces two methods related to abstract Record
class that are given as below.
(a)
RecordComponent[] getRecordComponents()
RecordComponent
objects representing all the record components of this record class.
(b)
boolean isRecord()
10. Creating and Importing a Custom Class with Name "Record"
The super class of allrecord
classes is java.lang.Record
class that is an abstract
class. All the classes of java.lang
package are imported by default in a class. Now let us understand how to import our own class named as Record
in a class.
Suppose we create a class named as
Record
in our package com.cp
as below.
package com.cp; public class Record { private String name; public Record(String name) { this.name = name; } public String getRecordName() { return name; } }
Record
class, we cannot import it as following.
import com.cp.*;
error: reference to Record is ambiguous
Record
class is also imported from java.lang.*
by default.
To avoid this ambiguity, we need to use fully qualified name of
Record
class as given below.
import com.cp.Record;
package com.concretepage; import com.cp.Record; public class MyApp { public static void main(String[] args) { Record r = new Record("MyRecord"); System.out.println(r.getRecordName()); } }
11. References
Record ClassesJEP 395: Records