Lombok: Sebagai Pengguna, saya ingin dapat menggunakan anotasi @CopyConstructor untuk menghilangkan kode boilerplate

Dibuat pada 1 Sep 2015  ·  39Komentar  ·  Sumber: projectlombok/lombok

Misalkan saya memiliki kelas dengan konstruktor salinan:

<strong i="6">@Data</strong>
class MyEntity {
    private String column;
    private String type;

    public MyEntity(MyEntity entity){
        this.column = entity.getColumn();
        this.type = entity.getType();
    }
}

Ada baiknya untuk menyingkirkan kode boilerplate dan menggantinya dengan anotasi @CopyConstructor agar Lombok membuat salinan konstruktor secara otomatis untuk saya.

<strong i="11">@Data</strong>
<strong i="12">@CopyConstructor</strong>
class MyEntity {
    private String column;
    private String type;
}

Reinier, apa pendapatmu tentang itu?

_PS_

Lebih baik lagi untuk memberikan anotasi dengan nilai yang menjelaskan jenis penyalinan:

<strong i="18">@Data</strong>
@CopyConstructor(type = SHALLOW) // or DEEP
class MyEntity {
    private String column;
    private String type;
}

Komentar yang paling membantu

Bagaimana dengan menggunakan @Builder(toBuilder = true) ? Dalam hal ini Anda dapat menggunakan

@Builder(toBuilder = true)
class Foo {
    // fields, etc
}

Foo foo = getReferenceToFooInstance();
Foo copy = foo.toBuilder().build();

Bukankah itu cukup?

Semua 39 komentar

Saya pikir itu adalah fitur yang sangat berguna; akan senang melihat itu :)
Hanya perlu sedikit perhatian, apakah itu dangkal atau dalam, dan bagaimana mengendalikannya.

@luanpotter Poin bagus! Itu selalu memungkinkan untuk menentukan tipe konstruktor salinan. Saya pikir akan mudah untuk mengimplementasikan fitur seperti itu di Lombok. Saya menemukan beberapa lib untuk mengkloning objek yang dapat berguna: kryo , cloning , dozer .

Dan di sini adalah API yang memungkinkan untuk fitur konstruktor salinan sehubungan dengan jenis salinan:

<strong i="11">@Data</strong>
@CopyConstructor(type = SHALLOW)
class MyEntity {
    private String column;
    private String type;
}
<strong i="14">@Documented</strong>
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
<strong i="15">@interface</strong> CopyConstructor {
    CopyConstructorType type() default CopyConstructorType.DEEP;
}
enum CopyConstructorType {
    DEEP,
    SHALLOW
}

Saya juga akan memberikan suara untuk anotasi untuk membuat copy constructor. Dalam kasus penggunaan khas saya, saya akan mengatakan bahwa saya menggunakan salinan dalam lebih dari 90% dari waktu, sehingga sepertinya default yang masuk akal (bagi saya).

+1

Ini dapat membantu menghindari beberapa bug pengkodean tangan yang bodoh.

Bagaimana dengan menggunakan @Builder(toBuilder = true) ? Dalam hal ini Anda dapat menggunakan

@Builder(toBuilder = true)
class Foo {
    // fields, etc
}

Foo foo = getReferenceToFooInstance();
Foo copy = foo.toBuilder().build();

Bukankah itu cukup?

@rspilker Adakah manfaat dalam pembangun di sini? Kelas @Data dapat diubah dan dapat dianggap sebagai pembangun itu sendiri (jika konstruktor salinan tersedia).

@rspilker Maaf, tidak tahu sudah ada fungsi @Builder )
Dingin! Ini adalah cara untuk pergi!

Saya berasumsi trik @Builder(toBuilder = true) hanya membuat salinan koleksi yang dangkal?

Harap berhenti mengeposkan komentar +1, dan gunakan tombol jempol di bawah kiriman asli.

Hai kawan,
Apakah ada rencana untuk fitur ini?
@rspilker :+1: tks, saya pikir toBuilder adalah alternatif yang dapat diterima.

Apakah Anda menerima PR? Ingin sekali melihat ini.

Sebelum Anda mulai mengerjakan permintaan tarik, pertama-tama kita perlu mencari cara untuk menangani salinan yang dalam. Juga, kita perlu mencari tahu mengapa orang ingin membuat salinan sama sekali. Dalam pengalaman saya, memiliki objek yang tidak dapat diubah mendapatkan lebih banyak daya tarik. Untuk salinan dangkal kita sudah memiliki trik toBuilder. Kesenjangan apa yang akan diisi oleh CopyConstructor?

@rspilker Hal salinan dalam pasti penting, tetapi perhatikan bahwa itu berlaku juga untuk konstruktor, setter, dan pengambil lain, di mana itu tidak dianggap sebagai pemblokir. Ini lebih penting, tetapi fitur ini dapat dimulai tanpa penyalinan yang dalam, misalnya, sebagai @CopyConstructor(value=SHALLOW) dengan SHALLOW sebagai default dan (untuk saat ini) satu-satunya anggota enum.

Untuk salinan dangkal kita sudah memiliki trik toBuilder.

Kami melakukannya, tetapi itu jelek dan tidak efisien. Ini sangat jelek karena Anda hanya perlu menyalin untuk objek yang bisa berubah, yang biasanya tidak memerlukan Builder . Ini tidak efisien karena melakukan penyalinan dua kali.

Penyalinan mendalam sangat rumit dan secara pribadi saya tidak berpikir itu tugas Lombok untuk melakukan ini.

Teknik umum adalah membuat serial dan deserialize menggunakan aliran objek karena sebagian besar grafik objek terlalu rumit. Anda kehilangan data sementara dengan cara ini. Tidak ada alasan bagi Lombok untuk melakukan ini untuk Anda, ada alat seperti Apache commons yang dapat melakukannya.

Cara lainnya adalah dengan melintasi grafik objek secara rekursif dan menyalin setiap objek dalam grafik. Ini seperti memberi anotasi secara rekursif pada konstruktor salinan dangkal. Di sini Anda harus menjaga koleksi karena mereka perlu menyalin elemen mereka secara mendalam. Karena tidak semua kelas di JDK mengizinkan fungsi ini, saya rasa itu tidak mungkin.

Saya setuju dengan Maaartinus untuk mengimplementasikan konstruktor salinan dangkal.

Silakan berhenti dengan komentar +1. Ini memberi tahu pelanggan dan menciptakan kebisingan. Gunakan emoji jempol ke atas sebagai gantinya.

Sebagai alternatif, mungkin rantai @Builder atau @CopyConstructure dimungkinkan - buat salinan dalam untuk bidang anggota yang juga dijelaskan dengan @CopyConstructor

Sebagai masalah preferensi, saya suka apa yang dilakukan Immutables ..

ImmutableValue.builder() .from(otherValue) // merges attribute value into builder .addBuz("b") .build();

@rspilker

Kesenjangan apa yang akan diisi oleh CopyConstructor?

Itu bisa memungkinkan untuk membuat instance kelas dari superclass-nya, memberikan solusi untuk masalah seperti ini .

Penyalinan dalam sangat rumit

@omega09
... dan agak kurang spesifik. Anda jelas bermaksud membuat grafik objek yang sama sekali baru, yang (kecuali untuk anggota yang tidak dapat diubah) tidak memiliki kesamaan dengan aslinya. Saya kira, yang biasanya diperlukan adalah semacam salinan kedalaman-satu : Objek saya berisi beberapa bagian yang bisa berubah seperti koleksi (atau beberapa omong kosong usang seperti Date ), yang "memiliki" . Anggota koleksi ini mungkin tidak dapat diubah atau objek lain, yang tidak "dimiliki" dan tidak perlu disalin. Biasanya, Anda tidak ingin menyalin semua anggota.

Contoh tipikal adalah keranjang belanja yang memiliki User yang berisi Multiset<Item> . Saat Anda membutuhkan salinan keranjang, Anda hanya ingin menyalin Multiset secara dangkal , karena pengguna dan item itu sendiri adalah entitas yang terpisah, yang harus tetap seperti saat Anda bermain dengan kereta.

Saya setuju, bahwa konstruktor salinan kedalaman penuh berada di luar lingkup Lombok, tetapi saya ingin mendapatkan konstruktor salinan kedalaman-satu suatu hari nanti. Ini masih agak rumit tanpa Lombok yang maha tahu untuk menyalin. Namun, dimungkinkan untuk membuatnya dapat dikonfigurasi:

<strong i="18">@Getter</strong> <strong i="19">@Setter</strong>
@CopyConstructor(value=DEPTH_ONE) // better name needed
class ShoppingCart {
    <strong i="20">@NoCopier</strong>
    private User owner;

    // known to Lombok, copied automatically
    private final Set<Discount> discounts = new HashSet<>();

    @Copier(MyCopiers.Multiset) // user-defined class containing the copying method
    // @Copier(HashMultiset::create) // <- this would be much nicer
    private final Multiset<Item> items = HashMultiset.create();
}

Satu-satunya argumen dari @Copier adalah Function<T, T> . Sekarang bahkan Android mendukung Java 8...

Atau, perkenalkan @CopyingMethod bekerja seperti yang dilakukan @ExtensionMethod : menyediakan kumpulan metode untuk dipilih.

Untuk kedua kalinya, berhentilah berkomentar dengan +1 dan acungkan jempol pada komentar teratas. Anda membuat banyak kebisingan untuk apa-apa.

@Maaartinus

Jadi delomboking hal-hal salinan, kelas Anda akan

<strong i="8">@Getter</strong> <strong i="9">@Setter</strong>
class ShoppingCart {

    public ShoppingCart(ShoppingCart cart) {
        ShoppingCart newCart = new ShoppingCart();
        newCart.setDiscounts(new HashSet<>(cart.getDiscounts());
        newCart.setItems(HashMultiset.create(cart.getItem());
    }

    private User owner;
    private final Set<Discount> discounts = new HashSet<>();
    private final Multiset<Item> items = HashMultiset.create();
}

?

@omega09 Semacam... apa yang Anda tulis tidak akan dikompilasi, karena discounts dan items adalah final . (*) Selain itu, Anda membuat instance baru ShoppingCart di konstruktor ShoppingCart . Dan Anda lupa user . Meskipun demikian, saya percaya, Anda punya ide yang benar.

public ShoppingCart(ShoppingCart cart) {
    user = cart.user;

    // was initially empty, otherwise we'd need also discounts.clear()
    discounts.addAll(cart.discounts);

    // with a final field, the <strong i="13">@Copier</strong> as specified won't work, but lets ignore it

    // VARIANT 1 (for a non-final field)
    // if lombok knew `HashMultiset` or if we could feed it with HashMultiset::create, then it'd use your line
    newCart.setItems(HashMultiset.create(cart.getItem());

    // VARIANT 2 (for a non-final field)
    // with @Copier(MyCopiers.Multiset) it would do
    newCart.setItems(MyCopiers.Multiset.apply(cart.multiset))
    // the user would most probably implement `apply` using `HashMultiset::create`
}

Ternyata lebih rumit dari yang saya kira, sebagian besar karena contoh saya tidak sesuai dengan apa yang saya pikirkan.

Btw., beberapa bahasa asing memiliki assign , yang menyalin konten dari satu instance ke instance lain. Hal ini memungkinkan untuk mensimulasikan copy constructor dengan mudah dan menggunakan kembali objek yang ada.


(*) Menggunakan final dengan koleksi yang dapat diubah yang diekspos ke luar terkadang masuk akal karena memungkinkan untuk memodifikasinya tanpa memberikan metode apa pun untuk itu. Kerugiannya adalah bahwa setiap pengguna kelas dapat menyimpan salinan dan memodifikasinya kapan saja nanti, yang menyebabkan sulit untuk menemukan bug. Tidak tahu mengapa saya melakukannya.

@Maaartinus

apa yang Anda tulis tidak akan dikompilasi, karena discounts dan items adalah final

Ya, saya benar-benar mengabaikannya :)

anda membuat instance baru ShoppingCart di konstruktor ShoppingCart

Ups, saya mengubah contoh beberapa kali dan tetap dari iterasi sebelumnya di mana saya menggunakan pendekatan pabrik:

public static ShoppingCart copyDepthOne(ShoppingCart cart) {
    ShoppingCart newCart = new ShoppingCart(); // now makes sense
    // add/set everything
    return newCart;
}

yang lebih merupakan wilayah @Builder (dan sudah ada beberapa masalah yang membahas ini).

Dan Anda lupa user .

Tapi itu ditandai dengan @NoCopier jadi saya tidak menyalinnya. Dalam contoh Anda, saya melihat bahwa yang Anda maksud adalah salinan kedalaman 0 (= dangkal). Jadi bagi saya sepertinya resolusinya adalah: jika @NoCopier buat salinan dangkal, jika tidak buat salinan kedalaman seperti yang ditentukan dalam @CopyConstructor(value) .

Secara naif saya akan melihat dalam pikiran saya sesuatu seperti ini:

<strong i="30">@Getter</strong> <strong i="31">@Setter</strong>
<strong i="32">@CopyConstructor</strong>
class ShoppingCart {

    // no annotation - no copy
    private Session session;

    @Copy(value = DEPTH_ZERO)
    private User owner;

    @Copy(value = DEPTH_ONE)
    private Collection<Discount> discounts = new CollectionImpl<>();

    @Copy(value = DEPTH_ONE, method = ForeignCollectionImpl::create) // let's assume this works somehow
    private ForeignCollection<Item> items = ForeignCollectionImpl.create();
}

yang akan membuat

ShoppingCart(ShoppingCart cart) {
    owner = cart.owner;

    // if we assume a copy constructor exists for the collection:
    discounts = new CollectionImpl<>(cart.getCollectionImpl())
    // or if we assume a setter/addAll exists for the collection's contents
    discounts = new CollectionImpl<>();
    discounts.addAll(cart.getDiscounts());

    // and now for the magic trick - is the given method a copy constructor or an empty constructor?
   items = ForeignCollectionImpl.create(cart.getItems());
}

TETAPI

  • Bagaimana jika saya membubuhi keterangan User owner dengan DEPTH_ONE ? Hasilkan owner = new User(cart.owner); ? Tidak
    ini masuk akal sebagian besar untuk koleksi? Apakah ini layak hanya untuk koleksi dan kotak pinggiran?
  • Apakah kelas DEPTH_ONE mendukung konstruktor salinan mereka sendiri? Apakah mereka mendukung setter? Saya mungkin dilindungi oleh pemeriksaan kompiler pada kode yang dihasilkan tetapi dapatkah Lombok memeriksa ini tanpa resolusi tipe? Saya tidak berpikir begitu.

Jika ini dapat dilakukan maka salinan dalam yang lengkap dapat dilakukan dengan menerapkan kedalaman satu salinan secara rekursif, yang akan menyelesaikan masalah dunia (ada serialisasi inti Java?). Untuk DEPTH_ZERO saya memberikan restu saya dan saya pikir saya bahkan bisa mengimplementasikannya sendiri, kecuali untuk kasus Edge. Untuk salinan yang lebih dalam yang bukan hanya ekspresi penugasan dan melibatkan pemanggilan, detailnya harus benar- benar diperbaiki.

@omega09

Tapi itu ditandai dengan @NoCopier jadi saya tidak menyalinnya.

Begitu ya, itu nama yang bodoh. Memang, objek tidak akan disalin sama sekali, hanya referensi untuk itu, jadi @ReferenceCopier mungkin lebih baik. Untuk apa yang Anda pahami, mungkin @CopyConstructor.Exclude bisa menjadi nama yang bagus.

// no annotation - no copy

Itu sangat rawan kesalahan. Selain itu, itu membuat @CopyConstructor tidak menyalin apa pun secara default!

Bagaimana jika saya membubuhi keterangan pemilik Pengguna dengan DEPTH_ONE ? Hasilkan owner = new User(cart.owner); ?

Saya rasa begitu. Jika ada penjelasan seperti itu.

Bukankah ini masuk akal sebagian besar untuk koleksi?

Ya.

Apakah kelas DEPTH_ONE mendukung konstruktor salinan mereka sendiri?

Lombok harus menangani kelas yang diketahuinya (JDK + Guava) dengan sempurna. Bagi yang lain, itu harus memiliki strategi default sederhana seperti memanggil konstruktor salinan mereka dan membiarkan pengguna menanganinya, jika tidak dikompilasi. Ketika kesalahan waktu kompilasi jelas, maka itu baik-baik saja. Jika itu harus menyebabkan kesalahan samar, maka segera menyerah dengan pesan waras yang meminta pengguna untuk memberikan mesin fotokopi mereka lebih baik.

Jika ini dapat dilakukan maka salinan dalam yang lengkap dapat dilakukan dengan menerapkan kedalaman satu salinan secara rekursif

Saya rasa tidak: Anda akan kehilangan identitas objek dan lingkaran mana pun akan mengarah ke grafik tak terbatas. IMHO salinan dalam yang sebenarnya sangat berlebihan, sejauh ini saya tidak pernah menggunakannya.

detailnya harus benar- benar disetrika.

Memang. Itu sebabnya saya menulis bahwa konstruktor dangkal harus dilakukan terlebih dahulu dan mandiri. Apa pun di luar itu adalah urutan besarnya lebih rumit; bahkan memahami apa yang harus dilakukan itu sulit. IMHO tidak mungkin melakukan sesuatu yang berguna (di luar salinan dangkal) tanpa membiarkan pengguna menentukan metode pembantu mereka sendiri (dan saya melihat hal-hal seperti @Copy(value=DEPTH_ONE) seperti pintasan untuk kasus umum).

Mungkin kita harus menulis mesin fotokopi menggunakan prosesor anotasi biasa (yang jauh lebih sederhana) atau melihat apakah seseorang sudah melakukannya. Atau lakukan dengan refleksi, yang bahkan lebih mudah. Kemudian kita akan memiliki implementasi referensi untuk dimainkan.

@Maaartinus

Jadi mari kita putuskan beberapa skema anotasi. Sepertinya saya bekerja dengan 3 opsi: kecualikan, dangkal, dan kedalaman 1. Haruskah yang terakhir menjadi default untuk koleksi* sedangkan untuk semua jenis lainnya, defaultnya dangkal? Apakah level ditentukan dalam anotasi kelas dan kemudian ditimpa di anotasi bidang?

*Jangan kira kita bisa mengecek apakah sebuah field merupakan koleksi di Lombok, sedangkan kita bisa dengan refleksi.

@omega09
IIUYC shallow pada bidang berarti menyalin referensi tetapi bukan objek. Itu membingungkan karena "dangkal" untuk seluruh objek berarti "referensi" untuk bidang. Demikian pula untuk kedalaman 1. Saya akan menyebutnya berbeda:

  • @CopyConstructor.Exclude : biarkan apa adanya, mungkin null
  • @CopyConstructor.Reference : salin referensi ke objek lama
  • @CopyConstructor.Copy :

    • untuk yang tidak dapat diubah ( String , Jambu yang tidak dapat diubah seperti ImmutableSet , ...), salin referensi

    • untuk koleksi dan peta lain yang diketahui , buat yang baru sebagai salinan dangkal (yaitu, mengacu pada objek yang sama dengan yang lama)

    • untuk kelas lain yang dikenal , lakukan apa yang diperlukan ( Date.clone atau serupa)

    • untuk hal lain, panggil konstruktor salinan mereka, yang mungkin atau mungkin tidak dikompilasi

  • @CopyConstructor.Copy(MyCopyingHelper.class) : memanggil MyCopyingHelper.copy(thisField) , yang mungkin atau mungkin tidak dikompilasi, seperti @ExtensionMethod

Di seluruh kelas, saya melihat tiga kemungkinan:

  • @CopyConstructor : salinan dangkal, menggunakan @CopyConstructor.Reference pada bidang secara default
  • @CopyConstructor(DEPTH_1) : salinan kedalaman 1, menggunakan @CopyConstructor.Copy pada bidang secara default
  • @CopyConstructor(MyCopyingHelper.class) : konstruktor yang ditentukan pengguna, menggunakan @CopyConstructor.Copy(MyCopyingHelper.class) pada bidang secara default

Gak nyangka bisa kita cek apakah field adalah kumpulan di Lombok

Sepakat. Saya hanya akan memeriksa kelas yang dikenal sesuai dengan tipe yang dideklarasikan.

@Maaartinus

Baiklah, saya akan membayar sesuatu akhir pekan ini.

@Maaartinus

Saya membuat garpu . Ringkasan tahap saat ini:

Anotasi baru

  • @CopyConstructor hanya berlaku di kelas. Memiliki properti Depth yang merupakan enum dengan 3 entri EXCLUDE , REFERENCE dan ONE . Standarnya Depth adalah REFERENCE .
  • @CopyConstructor.Exclude , @CopyConstructor.Reference dan @CopyConstructor.Copy hanya berlaku di bidang. @Copy memiliki properti Class<?> yang menentukan kelas pembantu penyalinan.

Saat ini hanya Exclude dan Reference yang didukung.

Penggunaan

  • Semua bidang diperlakukan dengan properti Depth dari anotasi kelas kecuali jika mereka menentukan miliknya sendiri.
  • Jika lebih dari satu anotasi bidang diterapkan, ini adalah kesalahan kompilasi.
  • Jika anotasi bidang diterapkan ke bidang static , ini adalah kesalahan kompilasi.
  • Jika anotasi bidang diterapkan ke bidang di kelas tanpa anotasi kelas, ini adalah peringatan kompilasi untuk anotasi yang tidak berarti.
  • Jika Exclude diterapkan ke bidang final yang diinisialisasi ke null itu adalah peringatan kompilasi untuk tidak menetapkan nilai dalam konstruktor. (Mungkin harus diubah untuk mengeluarkan peringatan bagi konstruktor dengan depth = EXCLUDE kecuali jika anotasi bidang eksplisit digunakan.)

Penerapan

  • Konstruktor yang dihasilkan adalah public dengan argumen tipe tipe beranotasi (duh). Mungkin perlu mengizinkan pemilihan tingkat akses.
  • Semua bidang yang tidak valid (misalnya, static ) atau yang diselesaikan menjadi EXCLUDE (secara implisit atau eksplisit) diabaikan.
  • Semua bidang yang diselesaikan menjadi REFERENCE diberikan tugas dari pengambil argumen konstruktor. Jika bidang salinan REFERENCE tidak memiliki pengambil, kesalahan kompilasi akan diberikan. Mungkin perlu mengizinkan useGetters = false .

Saat ini hanya berfungsi dengan ejc (Eclipse) . Ada juga ruang untuk pembersihan dan koreksi setelah menambahkan dukungan Copy .

Salin perilaku

Saya tidak yakin bagaimana memperlakukan tipe yang "diketahui". Koleksi dapat menggunakan addAll which can be used , tetapi bagaimana Anda tahu untuk jenis lain apa yang harus dilakukan? Periksa implementasi clone ?

Contoh

Kode berikut

@CopyConstructor(depth = Depth.EXCLUDE)
<strong i="62">@Getter</strong>
class Test {

    static int i;

    <strong i="63">@Reference</strong>
    boolean b;

    <strong i="64">@Reference</strong>
    List<String> list = new ArrayList<>();

    <strong i="65">@Exclude</strong>
    Object o;
}

setelah mendelombok anotasi CopyConstructor adalah

<strong i="69">@Getter</strong>
class Test {
    static int i;
    boolean b;
    List<String> list = new ArrayList<>();
    Object o;

    @java.lang.SuppressWarnings("all")
    @javax.annotation.Generated("lombok")
    public Test(final Test test) {
        super();
        this.b = test.isB();
        this.list = test.getList();
    }
}

Kenapa ini masih buka? Ini fitur yang sangat berguna memang.

@balajeetm Maksud Anda mengapa itu tidak diterapkan? Itu harus diselesaikan dan kemudian PR perlu ditinjau. Saya kurang lebih melupakannya sejak saya memposting implementasi awal. Bagian "Menyalin perilaku" posting sebelumnya berisi beberapa pertanyaan yang perlu dijawab.

@omega09 - Bisakah Anda membuat ringkasan pertanyaan terbuka mengenai fitur keren ini?

Bagaimana dengan parameter untuk mengontrol apakah akan memanggil @CopyConstructor dari superclass (alih-alih memanggil super() )? Ini akan memungkinkan untuk menyalin bidang dari superclass.

Saya baru saja mencoba Builder dan tidak berfungsi dengan baik, lihat juga: https://github.com/peichhorn/lombok-pg/issues/78 - itu tidak mempertimbangkan atribut yang diwarisi, yang berarti pada dasarnya tidak dapat digunakan untuk saya (ingin pengganti untuk klon()). Jadi saya juga lebih suka @CopyConstructor khusus, bersama dengan opsi untuk mengatur visibilitas ke pribadi.

Membuat klon yang dalam tidak mungkin: Tidak ada cara umum untuk mengkloning objek; Anda perlu tahu apa yang Anda hadapi. Integer, String, dll tidak dapat diubah dan klon yang dalam hanya harus menyalin referensi, meskipun kadang-kadang karena alasan eksotis Anda benar-benar ingin mengkloning dalam yang tidak dapat diubah dalam hal ini Anda memerlukan kode khusus.

array dan semacamnya membutuhkan perlakuan khusus untuk mengkloning. Anda tidak bisa hanya berkeliling dan memanggil clone() pada berbagai hal; clone() umumnya membuat klon dangkal, dan begitu Anda berkomitmen untuk membuat klon yang dalam, itu akan menjadi kura-kura sepenuhnya.

Jadi, satu-satunya hal yang layak yang dapat kita tambahkan adalah klon dangkal, dan toBuilder sudah cukup untuk kasus penggunaan itu.

Kami tidak akan menambahkan ini; tolong jangan buang waktu Anda dengan PR atau diskusi lebih lanjut.

toBuilder tidak dapat digunakan jika ada hierarki objek.

Apakah saya melewatkan sesuatu?

Ya.

Tentu saja Anda dapat menggunakan toBuilder dengan hierarki, pastikan semuanya
dalam hierarki memiliki pembangun / toBuilder dan Anda dapat melakukan pembangun bersarang
panggilan:

Diberikan objek tingkat atas dengan Daftar sebagai bidang dalam, yang berisi daun
node yang dibuat oleh metode bernama createLeaf():

TopLevel newtopLevel = topLevel.toBuilder()
.innerField(topLevel.getInnerField().stream()
.map(t -> t.toBuilder()
.leaf(createLeaf(t))
.membangun())
.collect(Collectors.toList()))
.membangun();

Satu-satunya saat Anda mendapat masalah dengan pola ini jika ada
referensi mundur ke objek tingkat atas, dan bahkan itu memiliki solusi.
(jika tidak terlalu cantik, tetapi tidak lebih buruk daripada jika Anda melakukan ini
cara konvensional.)

Pada Senin, 29 Okt 2018 pukul 14:47 Antonio Macrì [email protected]
menulis:

toBuilder tidak dapat digunakan jika ada hierarki objek.

Apakah saya melewatkan sesuatu?


Anda menerima ini karena Anda berlangganan utas ini.
Balas email ini secara langsung, lihat di GitHub
https://github.com/rzwitserloot/lombok/issues/908#issuecomment-433915647 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AAKCRTxwd3HARbpkcs3LX7d0-pl1YGo9ks5upwbggaJpZM4F1ZX-
.

--
"Jangan hanya melatih seni Anda, tetapi paksakan jalan Anda ke dalam rahasianya, untuk itu
dan pengetahuan dapat mengangkat manusia kepada yang ilahi."
--Ludwig von Beethoven

Dan @SuperBuilder akan mendapatkan dukungan untuk toBuilder dengan rilis berikutnya.

Ini adalah kasus persis yang saya miliki:

class Super {
    private int superVars;

    public Super(Super other) {
        // copy constructor
        this.superVars = other.superVars;
    }
}

class Sub extends Super {
    private String subVars;

    public Sub(Super s) {  // <-- Notice Super, not Sub
        super(s);
        this.subVars = "something else";
    }
}

toBuilder tidak dapat digunakan untuk saat ini.

Akankah SuperBuilder cocok untuk kasus ini?

Ya. Anda mungkin harus menyesuaikannya, tetapi itu harus memungkinkan.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat