Java Records
In JDK 14 was introduced a new type declaration called record
which is a restricted form of class. Ideal for data carrying, containig only constructor and accessors methods, immutable.
Example record representation:
public record Player(
String firstName,
String lastName,
Position position,
short jersey
) { }
Accessors
Each field of this record is automatically private
and final
. At the same time each component of the record gets public accessor method with the same name and type.
In this case those are:
Player::firstName();
Player::lastName();
Player::position();
Player::jersey();
Constructors
Record has public constructor derived from it’s components.
var player = new Player("Json", "Hardcoded", Position.QB, (short) 3);
At the same time it’s possible to define additional constructors.
Like this one to ensure that the firstName
and lastName
are not null
:
public record Player(
String firstName,
String lastName,
Position position,
short jersey) {
public Player {
Objects.requireNonNull(firstName);
Objects.requireNonNull(lastName);
}
}
Or separate constructor with different arguments:
public record Player(
String firstName,
String lastName,
Position position,
short jersey) {
public Player(String firstName, String lastName) {
this(firstName, lastName, null, Short.MIN_VALUE);
}
}
Records constructors follow the same rules and requirements as regular Java classes.
Interfaces
Record can’t extend class but can implement interfaces.
public record Player(
String firstName,
String lastName,
Position position,
short jersey) implements Whatever, Nice {
public static String FOO_BAR = "FooBar";
public static Player quarterback(String sirstName, String lastName) {
return new Player(sirstName, lastName, Position.QB, (short) 6);
}
}
Equals & Hash Code
Additionally record get equals
and hashCode
generated.
Implementation of equals
return true
only when supplied object has the same type and all it’s fields match corresponding ones.
@Test
public void shouldBeEqual() {
// given
var player1 = new Player("Json", "Hardcoded", Position.QB, (short) 6);
var player2 = new Player("Json", "Hardcoded", Position.QB, (short) 6);
// when
var actual = player1.equals(player2);
// then
assertTrue("Players must be equal", actual);
}
Implementation of hashCode
returns the same value for two records if all their fields match.
@Test
public void shouldHaveSameHashCode() {
// given
var player1 = new Player("Json", "Hardcoded", Position.QB, (short) 6);
var player2 = new Player("Json", "Hardcoded", Position.QB, (short) 6);
// when
var player1Hash = player1.hashCode();
var player2Hash = player2.hashCode();
// then
assertEquals("Players must have same hash code", player1Hash, player2Hash);
}
To String
Another nice to have feature is pretty human readable toString
implementation containig the field name and value pairs.
Player[firstName=Json, lastName=Hardcoded, position=QB, jersey=6]
Static
Static variables are declared in the same way as it’s done in class.
public record Player(
String firstName,
String lastName,
Position position,
short jersey) {
public static String FOO_BAR = "FooBar";
}
Static methods can be declared in a similar way.
public record Player(
String firstName,
String lastName,
Position position,
short jersey) {
public static Player quarterback(String sirstName, String lastName) {
return new Player(sirstName, lastName, Position.QB, (short) 6);
}
}
Those can then be used as following
var fooBar = Player.FOO_BAR;
var quarterbackPlayer = Player.quarterback("Json", "Hardcoded");
Restrictions
- No inheritance, record can’t extend class.
- No instance fields other that those declared in record component list (only static fields allowed)
- Record can’t be
abstract
as those are implicitelyfinal
- All record components are implicitely
final
- Can be declared inside classes and are implicitely
static
- Can implement interfaces
- Can be generic
- Can contain nested types
- Can have components annotated
- Can be annoted itself
Conclusion
Another awesome addition to Java language tool belt, one more step towards reduction of boilerplate code, great alternative to old POJO used as DTOs.