I would like to know how to rewrite this class
public class ClassA {
private final String foo;
private final String bar;
public ClassA(String foo) {
this.foo = foo;
this.bar = foo.toUpperCase();
}
// getters...
}
as a record class.
The best I've managed to do is this
public record ClassA(String foo, String bar) {
public ClassA(String foo) {
this(foo, foo.toUpperCase());
}
}
The problem is that this solution creates two constructors while I want only one which accepts the string foo
CodePudding user response:
Record classes always have a so-called canonical constructor, which expects arguments for all the field you've declared. This constructor would be generated by the compiler by default, but you can provide your own one, the key point: a canonical constructor is available for every record at runtime.
Here's a quote from the Java Language Specification:
To ensure proper initialization of its record components, a record class does not implicitly declare a default constructor (§8.8.9). Instead, a record class has a canonical constructor, declared explicitly or implicitly, that initializes all the component fields of the record class.
All non-canonical constructors, which are constructors with signatures that differ from the canonical, like your case constructor that expects a single argument ClassA(String)
, should delegate the call to the canonical constructor using so-called explicit constructor invocation, i.e. using this()
(precisely as you've done), otherwise such constructor would not compile.
A record declaration may contain declarations of constructors that are not canonical constructors. The body of every non-canonical constructor in a record declaration must start with an alternate constructor invocation (
§8.8.7.1
), or a compile-time error occurs.
Conclusion: since you've declared a record that has two fields, and you also need a non-canonical constructor expecting one argument, there would be two constructors: canonical and a non-canonical. There are no workarounds.