The following are quick features of Java Records:
Records cannot extend other classes
class Human {
}
public record Person(String name, String gender, int age) extends Human {
}
$ javac Person.java Person.java:4: error: '{' expected public record Person(String name, String gender, int age) extends Human { ^ 1 error
Note that a record class already extends java.lang.Record (implicitly).
Records are final
Records are implicitly final and cannot be extended.
public record Person(String name, String gender, int age) {
}
class Employee extends Person {
public Employee(String name, String gender, int age) {
super(name, gender, age);
}
}
$ javac Person.java Person.java:4: error: cannot inherit from final Person class Employee extends Person { ^ 1 error
Records can implement interfaces
import java.io.Serializable;
import java.util.Arrays;
public record Person(String name, String gender, int age) implements Serializable {
public static void main(String[] args) {
System.out.println("Interfaces implemented by Person");
Arrays.stream(Person.class.getInterfaces()).forEach(System.out::println);
}
}
$ javac Person.java $ java Person Interfaces implemented by Person interface java.io.Serializable
Records cannot create extra instance fields
public record Person(String name, String gender, int age) {
private int height;
}
$ javac Person.java Person.java:3: error: field declaration must be static private int height; ^ (consider replacing field with record component) 1 error
The components of a record are implicitly final
public record Person(String name) {
public void changeName(String newName){
this.name = newName;
}
}
$ javac Person.java Person.java:5: error: cannot assign a value to final variable name this.name = newName; ^ 1 error
Records can have static fields
public record Person(String name, String gender, int age) {
private static int count = 10;
public static void main(String[] args) {
Person person = new Person("John", "Male", 34);
System.out.println(person);
System.out.println(Person.count);
}
}
$ javac Person.java $ java Person Person[name=John, gender=Male, age=34] 10
The static methods, static fields, static initializers are allowed
public record Person() {
static int count;
static{
count = 20;
}
public static void showCount(){
System.out.println(count);
}
public static void main(String[] args) {
Person.showCount();
}
}
$ javac Person.java $ java Person 20
We can declare constructors
If we want our record's constructor to do more than initializing its private fields, we can define a custom constructor for the record. However, unlike a class constructor, a record constructor doesn't have a formal parameter list; this is called a compact constructor.
The primary reasons to provide an explicit declaration of the constructor methods are to validate constructor arguments,
import java.util.Objects;
public record Person(String name, String gender, int age) {
public Person {
Objects.requireNonNull(name);
Objects.requireNonNull(gender);
if (age <= 0) {
throw new IllegalArgumentException("Age must be greater than 0");
}
}
public static void main(String[] args) {
new Person("Tina", "female", 0);
}
}
$ javac Person.java $ java Person Exception in thread "main" java.lang.IllegalArgumentException: Age must be greater than 0 at Person.<init>(Person.java:8) at Person.main(Person.java:13)
We can add explicit accessors
We can also declare a getter which will replace the implicit getter:
public record Person(String name, String gender, int age) {
public int age() {
return age < 0 ? 0 : age;
}
public static void main(String[] args) {
Person person = new Person("Joe", "Male", -10);
System.out.println(person.age());
}
}
$ javac Person.java $ java Person 0
Extra instance methods are allowed
public record Person(String name) {
public void printName(){
System.out.println(name);
}
public static void main(String[] args) {
Person person = new Person("Joe");
person.printName();
}
}
$ javac Person.java $ java Person Joe
Nested records are allowed
You can declare records inside a class. The nested records are implicitly static.
import java.lang.reflect.Modifier;
public class MyClass {
public record Person(String name) {
}
public static void main(String[] args) {
Person person = new Person("Joe");
System.out.println(person);
Class<?> enclosingClass = Person.class.getEnclosingClass();
System.out.println("Enclosing class: " + enclosingClass.getName());
String modifier = Modifier.toString(Person.class.getModifiers());
System.out.println("Person modifiers: " + modifier);
}
}
$ javac MyClass.java $ java MyClass Person[name=Joe] Enclosing class: MyClass Person modifiers: public static final
Generic records are allowed
public record Line<N extends Number>(N length) {
public static void main(String[] args) {
Line<Double> line = new Line<>(5.3);
System.out.println(line);
}
}
$ javac Line.java $ java Line Line[length=5.3]
Records can be annotated
We can annotate a record. We can also annotate record's individual components .
import java.beans.JavaBean;
import java.lang.reflect.Field;
import java.util.Arrays;
@JavaBean
public record Person(@Deprecated String name) {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
System.out.println("-- Class annotations --");
Arrays.stream(Person.class.getDeclaredAnnotations())
.forEach(System.out::println);
System.out.println("-- Fields annotations --");
Arrays.stream(Person.class.getDeclaredFields())
.peek(x -> System.out.println("Field: " + x))
.map(Field::getDeclaredAnnotations)
.forEach(annotations -> System.out.println("Annotations: " + Arrays.toString(annotations)));
System.out.println("-- constructor annotation --");
Arrays.stream(Person.class.getDeclaredConstructor(String.class).getParameterAnnotations())
.forEach(annotations -> System.out.println(Arrays.toString(annotations)));
}
}
$ javac Person.java $ java Person -- Class annotations -- @java.beans.JavaBean(defaultProperty="", description="", defaultEventSet="") -- Fields annotations -- Field: private final java.lang.String Person.name Annotations: [@java.lang.Deprecated(forRemoval=false, since="")] -- constructor annotation -- [@java.lang.Deprecated(forRemoval=false, since="")]
Records cannot be abstract
public abstract record PersonPerson(String name) {
}
$ javac Person.java Person.java:2: error: modifier abstract not allowed here public abstract record Person(String name) { ^ 1 error
|