Reputation: 481
Creating immutable data structures, I really like the concept of Scala, where you can enforce object instantiation only via factory method in this way using case class (having a private canonical constructor) and companion object.
final case class Foo private(a: Int)
object Foo {
def apply(left: Int, right: Int) = Foo(left + right)
}
With Java 14, the concept of records have been introduced, providing most of Scala's case class features.
However, making the canonical constructor of records private
seems to be a bit cumbersome... Is there any way to achieve the same behavior with Java's records?
Upvotes: 38
Views: 17733
Reputation: 1847
In case, you want to make some sanity checks (or other additions) in factory method, you can use Compact constructor of record (i.e. constructor without parameters part). For example:
record HelloWorld(String message) {
public HelloWorld {
java.util.Objects.requireNonNull(message);
}
}
Through it will not hide canonical constructor, but it will "append" it with code provided (sanity checks, automatic registrations, ...)
Record cannot hide its canonical constructor like it is possible in case class from scala. "java" way for doing this is using class with private constructor:
public class Foo {
private final Integer a;
private Foo(Integer a) {
this.a = a;
}
public Foo of(Integer left, Integer right) {
return new Foo(left + right);
}
}
Through using opinionated lombok library, you can lower down boilerplate to scala level:
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class Foo {
private final Integer a;
public Foo of(Integer left, Integer right) {
return new Foo(left + right);
}
}
If you are already using lombok, you can be interested in its immutable annotation called @Value.
Upvotes: 13