Construir um objeto a partir de um existente usando lombok

105

Digamos que eu tenha uma aula com anotações lombok como

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

Eu sei que posso fazer:

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

Existe uma maneira fácil de criar um objeto de Foo usando o objeto existente como modelo e alterando uma de suas propriedades?

Algo como:

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

Não consigo encontrar isso na documentação do lombok.

Mustafa
fonte

Respostas:

232

Você pode usar o toBuilderparâmetro para fornecer um toBuilder()método às suas instâncias .

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

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

Da documentação :

Se estiver usando @Builder para gerar construtores para produzir instâncias de sua própria classe (este é sempre o caso, a menos que adicione @Builder a um método que não retorna seu próprio tipo), você pode usar @Builder (toBuilder = true) para também gerar um método de instância em sua classe chamado toBuilder (); ele cria um novo construtor que começa com todos os valores desta instância.

Isenção de responsabilidade: eu sou um desenvolvedor lombok.

Roel Spilker
fonte
12
@Mustafa Há também @Wither, que é mais eficiente para alterações de campo único: Foo f1 = f0.withX(42).
maaartinus
@maaartinus acho que @Withergera com * métodos que sempre retorna um novo objeto, ao invés de definir o campo do objeto existente. Isso é de baixa eficiência.
MGhostSoft
3
@MGhostSoft Obviamente, estou assumindo que a meta é criar um novo objeto. Assim, nós, objetos tão comuns como imutáveis, somos usados ​​cada vez mais. ++ × Para alterar um único campo, @Witheré melhor. Por mais de dois, toBuilderganha. Veja minha resposta abaixo.
maaartinus de
2
E para zero campos (ou seja, uma cópia do objeto sem quaisquer alterações), @Withernão funcionará de todo, mas funcionaria .toBuilder().build().
M. Justin
40

Existe uma maneira fácil de criar um objeto de Foo usando o objeto existente como modelo e alterando uma de suas propriedades? ( ênfase minha )

Se você realmente deseja alterar uma única propriedade, existe uma maneira mais agradável e eficiente:

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

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

A murcha não cria lixo, mas pode mudar apenas um único campo. Para alterar muitos campos, você pode usar

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

e produzir toneladas de lixo (todos resultados intermediários), mas do que toBuilderé mais eficiente e mais natural.

NOTA: As versões mais antigas do lombok usavam @Witheranotações. Veja o início da documentação .

maaartinus
fonte
1
isso realmente criaria tanto lixo? Acho que são todas cópias superficiais, exceto para o campo que você está substituindo (contando com a noção de que você já tornará o objeto imutável, se for o que se pretende). O "lixo" será principalmente as referências do objeto de nível superior descartado (embora eu ache que muitos primitivos também podem resultar em mais lixo).
jm0
1
@ jm0 Claro, são cópias superficiais. Por "toneladas de lixo", quero dizer n-1objetos para uma série de nchamadas withSomething. Um objeto custa algo como alguns bytes mais 4 ou 8 bytes por referência mais 1 a 8 bytes por primitivo. Portanto, estamos falando de dezenas de bytes por chamada. Não é grande coisa, geralmente.
maaartinus de