Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do Java records have accessor methods instead of public final fields?

JEP-395 says

a record class acquires many standard members automatically:

  • For each component in the header, two members: a public accessor method with the same name and return type as the component, and a private final field with the same type as the component;

If a generated final field has got the same name as the accessor method, why isn't a public final field generated instead?

like image 528
Donggi Kim Avatar asked Dec 02 '25 03:12

Donggi Kim


2 Answers

Records can implement interfaces, so the accessor of a record could be an implementation of an interface method. Furthermore using accessors instead of direct field access provides more flexibility, for example you can replace an accessor that directly returns a field with an accessor that derives a value in some way (or vice versa).

Records also allow you to override accessors to - instead of just plainly returning the field - do something extra. Making records use direct field access would restrict and limit what you could do with records, and thus limit their usefulness, while having accessors offers you the baseline offered by direct field access with the ability to do more if necessary.

To quote an example provided by Holger in the comments:

the classes public record R(int a, int b) { public int c() { return …; }} and public record R(int a, int c) { public int b() { return …; }} provide the same API, regardless of their internal representation.

In short, generating accessors for fields offers more flexibility and features than direct field access. The same also applies to plain immutable classes.

Another reason is provided by Brian Goetz in the comments on this answer:

Without the ability to override accessors, records would be unable to properly support mutable objects (such as arrays) as components. If you have an array component, you may want to perform a defensive copy in the constructor and accessor (which would also require overriding equals, in order to preserve the specification of Record); if it was a public final field, you could not encapsulate the mutability of your components

like image 74
Mark Rotteveel Avatar answered Dec 04 '25 15:12

Mark Rotteveel


I think a key factor in this decision was that you now have the ability to override the Record's getters:

public record MyRecord(String myProperty) {
    @Override
    public String myProperty() {
        return "The property is " + myProperty;
    }
}

Something like this would not be possible with public final fields.

like image 43
Moritz Avatar answered Dec 04 '25 16:12

Moritz