Xây dựng một đối tượng từ một đối tượng hiện có bằng lombok


102

Hãy nói rằng tôi có một lớp được chú thích lombok như

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

Tôi biết tôi có thể làm:

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

Có cách nào dễ dàng để tạo một đối tượng Foo bằng cách sử dụng đối tượng hiện có làm mẫu và thay đổi một trong các thuộc tính của nó không?

Cái gì đó như:

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

Tôi không thể tìm thấy điều này trong tài liệu lombok.

Câu trả lời:


225

Bạn có thể sử dụng toBuildertham số để cung cấp cho các trường hợp của mình một toBuilder()phương thức.

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

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

Từ tài liệu :

Nếu sử dụng @Builder để tạo trình xây dựng nhằm tạo ra các phiên bản của lớp riêng của bạn (trường hợp này luôn xảy ra trừ khi thêm @Builder vào một phương thức không trả về kiểu của riêng bạn), bạn có thể sử dụng @Builder (toBuilder = true) để tạo một phương thức thể hiện trong lớp của bạn được gọi là toBuilder (); nó tạo ra một trình tạo mới bắt đầu với tất cả các giá trị của trường hợp này.

Tuyên bố từ chối trách nhiệm: Tôi là nhà phát triển lombok.


11
@Mustafa Ngoài ra còn có @Wither, đó là hiệu quả hơn cho những thay đổi lĩnh vực duy nhất: Foo f1 = f0.withX(42).
maaartinus

@maaartinus Tôi nghĩ rằng @Withertạo bằng các phương thức * luôn trả về một đối tượng mới, thay vì đặt trường của đối tượng hiện có. Điều này có hiệu quả thấp.
MGhostSoft

2
@MGhostSoft Rõ ràng là tôi đang giả định rằng việc tạo một đối tượng mới là mục tiêu chính. Vì vậy, chúng ta khá phổ biến khi các đối tượng bất biến được sử dụng ngày càng nhiều. ++ × @WitherTốt nhất là để thay đổi một trường . Nhiều hơn hai, toBuilderchiến thắng. Xem câu trả lời của tôi dưới đây.
maaartinus

2
Và đối với các trường không (tức là một bản sao đối tượng mà không có bất kỳ thay đổi nào), @Withersẽ không hoạt động nhưng sẽ không hoạt động .toBuilder().build().
M. Justin

38

Có cách nào dễ dàng để tạo một đối tượng Foo bằng cách sử dụng đối tượng hiện có làm mẫu và thay đổi một trong các thuộc tính của nó không? ( nhấn mạnh của tôi )

Nếu bạn thực sự muốn thay đổi một thuộc tính, thì có một cách tốt hơn và hiệu quả hơn:

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

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

Khô héo không tạo ra rác, nhưng nó có thể thay đổi chỉ một trường duy nhất. Để thay đổi nhiều trường, bạn có thể sử dụng

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

và tạo ra hàng tấn rác (tất cả các kết quả trung gian) nhưng toBuilderhiệu quả hơn và tự nhiên hơn.

LƯU Ý: Các phiên bản cũ hơn của lombok đã sử dụng @Witherchú thích. Xem phần đầu của tài liệu .


1
nó sẽ thực sự tạo ra nhiều rác? Tôi nghĩ rằng đó là tất cả các bản sao cạn ngoại trừ trường bạn đang thay thế (dựa trên khái niệm rằng bạn sẽ làm cho đối tượng trở nên bất biến nếu đó là những gì dự định). "Rác" chủ yếu sẽ là các tham chiếu của đối tượng cấp cao nhất bị loại bỏ (mặc dù tôi đoán rằng rất nhiều nguyên thủy cũng có thể dẫn đến nhiều rác hơn).
jm0

1
@ jm0 Chắc chắn, đó là tất cả các bản sao cạn. Với "tấn rác", ý tôi là n-1các đối tượng cho một loạt các nlệnh gọi tới withSomething. Một đối tượng có giá như một vài byte cộng với 4 hoặc 8 byte cho mỗi tham chiếu cộng với 1 đến 8 byte cho mỗi nguyên thủy. Vì vậy, chúng ta đang nói về hàng chục byte mỗi cuộc gọi. Không có vấn đề lớn, thường.
maaartinus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.