Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Record Custom Constructor Selective Parameters

Tags:

java

record

I have a record:

public record Thing(
   Boolean field1,
   EnumType field2,
   int field3,
   String, field4
   . . .

I'm adding new fields to Thing a lot, which breaks all my code that uses the canonical constructor, and the fields are piling up, which makes the canonical constructor increasingly awkward to use.

What I'd like to do is be able to pass in specific values for arbitrary fields:

new Thing(field3 = 1, field4 = "XXX");
new Thing(field1 = true, field2 = ENUMVALUE);

Now, I know I can do constructors like:

Thing(int i, String s) ...
Thing(Boolean b, EnumType, e) ...
. . .
new Thing(1, "XXX");
new Thing(true, ENUMVALUE);

But it's really a situation of not knowing which fields I want to override the default values for. The only thing I've been able to come up with so far is turning Thing into a regular object so I can do something like:

new Thing().setField1(true).setField4("Blah");

Which is kind of a bummer because I don't want the values to be mutable once initialized.

like image 693
user3810626 Avatar asked Oct 15 '25 22:10

user3810626


1 Answers

Unfortunately Java does not have named arguments (at least at this point in time). What we can do to overcome this missing language feature is to use the builder pattern.

For records we could do something like this:

public record Thing(Boolean field, int field2, String field3) {

    private Thing(ThingBuilder thingBuilder) {
        this(thingBuilder.field, thingBuilder.field2, thingBuilder.field3);
    }

    public static class ThingBuilder {
        // We can set default values for the fields
        private Boolean field = false;
        private int field2;
        private String field3 = "";

        public ThingBuilder() {}

        public ThingBuilder field(Boolean field) {
            this.field = field;
            return this;
        }

        public ThingBuilder field2(int field) {
            this.field2 = field;
            return this;
        }

        public ThingBuilder field3(String field) {
            this.field3 = field;
            return this;
        }

        public Thing build() {
            return new Thing(this);
        }
    }
}

We can build Thing instances in the following way:

Thing thing = new Thing.ThingBuilder().field(true).field2(2).field3("some string").build();

Also, we can omit some fields and have them use their default values:

Thing thing = new Thing.ThingBuilder().field3("some string").build();
like image 163
Ervin Szilagyi Avatar answered Oct 17 '25 11:10

Ervin Szilagyi