Construye un objeto a partir de uno existente usando lombok

100

Digamos que tengo una clase anotada en lombok como

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

Sé que puedo hacer:

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

¿Existe una manera fácil de crear un objeto de Foo usando el objeto existente como plantilla y cambiando una de sus propiedades?

Algo como:

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

No puedo encontrar esto en la documentación de lombok.

Mustafa
fuente

Respuestas:

223

Puede utilizar el toBuilderparámetro para dar un toBuilder()método a sus instancias .

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

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

De la documentación :

Si usa @Builder para generar constructores para producir instancias de su propia clase (este es siempre el caso a menos que agregue @Builder a un método que no devuelve su propio tipo), puede usar @Builder (toBuilder = true) para generar también un método de instancia en su clase llamado toBuilder (); crea un nuevo constructor que comienza con todos los valores de esta instancia.

Descargo de responsabilidad: soy un desarrollador de lombok.

Roel Spilker
fuente
11
@Mustafa También hay @Wither, que es más eficiente para los cambios de campo individuales: Foo f1 = f0.withX(42).
maaartinus
@maaartinus Creo que @Withergenera con * métodos que siempre devuelven un nuevo objeto, en lugar de establecer el campo del objeto existente. Esto es de baja eficiencia.
MGhostSoft
2
@MGhostSoft Obviamente estoy asumiendo que el objetivo es crear un nuevo objeto. Por eso somos bastante comunes como objetos inmutables que se utilizan cada vez más. ++ × Para cambiar un solo campo, @Witheres mejor. Fot más de dos, toBuildergana. Vea mi respuesta a continuación.
maaartinus
2
Y para campos cero (es decir, una copia de objeto sin cambios), @Witherno funcionará en absoluto, pero lo .toBuilder().build()haría.
M. Justin
38

¿Existe una manera fácil de crear un objeto de Foo usando el objeto existente como plantilla y cambiando una de sus propiedades? ( énfasis mío )

Si realmente desea cambiar una sola propiedad, existe una forma más agradable y eficiente:

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

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

El marchitamiento no crea basura, pero puede cambiar solo un campo. Para cambiar muchos campos, puede usar

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

y producir toneladas de basura (todos resultados intermedios) pero que toBuilderes más eficiente y más natural.

NOTA: Las versiones anteriores de lombok han utilizado la @Witheranotación. Consulte el comienzo de la documentación .

maaartinus
fuente
1
¿realmente crearía tanta basura? Creo que todas son copias superficiales, excepto el campo que está reemplazando (confiando en la noción de que hará que el objeto sea inmutable si eso es lo que se pretende). La "basura" será principalmente las referencias del objeto de nivel superior descartado (aunque supongo que muchas primitivas podrían resultar en más basura también).
jm0
1
@ jm0 Seguro, todas son copias superficiales. Por "toneladas de basura" me refiero a n-1objetos para una serie de nllamadas withSomething. Un objeto cuesta algo así como unos pocos bytes más 4 u 8 bytes por referencia más 1 a 8 bytes por primitiva. Entonces estamos hablando de decenas de bytes por llamada. No es gran cosa, por lo general.
maaartinus