Erstellen Sie mit lombok ein Objekt aus einem vorhandenen

99

Nehmen wir an, ich habe eine mit Lombok kommentierte Klasse wie

@Builder
class Band {
   String name;
   String type;
}

Ich weiß, dass ich tun kann:

Band rollingStones = Band.builder().name("Rolling Stones").type("Rock Band").build();

Gibt es eine einfache Möglichkeit, ein Objekt von Foo zu erstellen, indem das vorhandene Objekt als Vorlage verwendet und eine seiner Eigenschaften geändert wird?

Etwas wie:

Band nirvana = Band.builder(rollingStones).name("Nirvana");

Ich kann das nicht in der Lombok-Dokumentation finden.

Mustafa
quelle

Antworten:

222

Mit dem toBuilderParameter können Sie Ihren Instanzen eine toBuilder()Methode geben.

@Builder(toBuilder=true)
class Foo {
   int x;
   ...
}

Foo f0 = Foo.builder().build();
Foo f1 = f0.toBuilder().x(42).build();

Aus der Dokumentation :

Wenn Sie mit @Builder Builder generieren, um Instanzen Ihrer eigenen Klasse zu erstellen (dies ist immer der Fall, es sei denn, Sie fügen @Builder zu einer Methode hinzu, die keinen eigenen Typ zurückgibt), können Sie mit @Builder (toBuilder = true) auch generieren eine Instanzmethode in Ihrer Klasse namens toBuilder (); Es wird ein neuer Builder erstellt, der mit allen Werten dieser Instanz beginnt.

Haftungsausschluss: Ich bin ein Lombok-Entwickler.

Roel Spilker
quelle
10
@Mustafa Es gibt auch @Wither, was für einzelne Feldänderungen effizienter ist : Foo f1 = f0.withX(42).
Maaartinus
@maaartinus @Withergeneriert meiner Meinung nach mit * Methoden, die immer ein neues Objekt zurückgeben, anstatt das Feld des vorhandenen Objekts festzulegen . Dies ist von geringer Effizienz.
MGhostSoft
2
@MGhostSoft Ich gehe offensichtlich davon aus, dass das Erstellen eines neuen Objekts das Ziel ist. Daher werden wir ziemlich häufig als unveränderliche Objekte verwendet. ++ × Zum Ändern eines einzelnen Feldes @Witherist am besten. Fot mehr als zwei, toBuildergewinnt. Siehe meine Antwort unten.
Maaartinus
2
Und für Nullfelder (dh eine Objektkopie ohne Änderungen) @Witherfunktioniert das überhaupt nicht, .toBuilder().build()würde es aber tun.
M. Justin
38

Gibt es eine einfache Möglichkeit, ein Objekt von Foo zu erstellen, indem das vorhandene Objekt als Vorlage verwendet und eine seiner Eigenschaften geändert wird? ( Hervorhebung von mir )

Wenn Sie wirklich eine einzelne Eigenschaft ändern möchten, gibt es einen schöneren und effizienteren Weg:

@With
class Band {
   String name;
   String type;
}

Band nirvana = rollingStones.withName("Nirvana");

Der Widerrist erzeugt keinen Müll, kann aber nur ein einziges Feld ändern. Zum Ändern vieler Felder können Sie verwenden

withA(a).withB(b).withC(c)....

und produzieren Tonnen Müll (alle Zwischenergebnisse), aber dann toBuilderist effizienter und natürlicher.

HINWEIS: Ältere Versionen von Lombok haben @WitherAnmerkungen verwendet. Siehe Anfang der Dokumentation .

Maaartinus
quelle
1
würde es wirklich so viel Müll verursachen? Ich denke, es sind alles flache Kopien mit Ausnahme des Feldes, das Sie ersetzen (unter der Annahme, dass Sie das Objekt bereits unveränderlich machen, wenn dies beabsichtigt ist). Der "Müll" ist meistens die Referenz des verworfenen Objekts der obersten Ebene (obwohl ich denke, dass viele Grundelemente auch zu mehr Müll führen könnten).
jm0
1
@ jm0 Klar, es sind alles flache Kopien. Mit "Tonnen Müll" meinte ich n-1Objekte für eine Reihe von nAnrufen an withSomething. Ein Objekt kostet ungefähr ein paar Bytes plus 4 oder 8 Bytes pro Referenz plus 1 bis 8 Bytes pro Grundelement. Wir sprechen also von zehn Bytes pro Anruf. Normalerweise keine große Sache.
Maaartinus