Tulis Kode Java Bebas Lemak dengan Project Lombok

Diterbitkan: 2022-03-11

Ada sejumlah alat dan perpustakaan yang saya tidak dapat membayangkan diri saya menulis kode Java tanpa hari ini. Secara tradisional, hal-hal seperti Google Guava atau Joda Time (setidaknya untuk era pra Java 8) adalah salah satu dependensi yang akhirnya saya lemparkan ke proyek saya hampir sepanjang waktu, terlepas dari domain spesifik yang ada.

Lombok pasti layak mendapatkan tempatnya di POM atau Gradle build saya juga, meskipun tidak menjadi utilitas perpustakaan/kerangka kerja yang khas. Lombok telah ada cukup lama sekarang (pertama kali dirilis pada tahun 2009) dan telah berkembang pesat sejak saat itu. Namun, saya selalu merasa bahwa ini layak mendapat perhatian lebih—ini adalah cara yang luar biasa untuk menangani verbositas alami Java.

Dalam posting ini, kita akan mengeksplorasi apa yang membuat Lombok menjadi alat yang berguna.

Proyek Lombok

Java memiliki banyak hal yang terjadi di luar JVM itu sendiri, yang merupakan bagian dari perangkat lunak yang luar biasa. Java sudah matang dan berkinerja, dan komunitas serta ekosistem di sekitarnya sangat besar dan hidup.

Namun, sebagai bahasa pemrograman, Java memiliki beberapa keistimewaannya sendiri serta pilihan desain yang dapat membuatnya agak bertele-tele. Tambahkan beberapa konstruksi dan pola kelas yang sering perlu digunakan oleh pengembang Java dan kami sering berakhir dengan banyak baris kode yang membawa sedikit atau tidak ada nilai nyata selain mematuhi beberapa rangkaian batasan atau konvensi kerangka kerja.

Di sinilah Lombok berperan. Ini memungkinkan kita untuk secara drastis mengurangi jumlah kode "boilerplate" yang perlu kita tulis. Kreator Lombok adalah pasangan yang sangat cerdas, dan tentu saja memiliki selera humor—Anda tidak boleh melewatkan intro yang mereka buat di konferensi sebelumnya!

Mari kita lihat bagaimana Lombok melakukan keajaibannya dan beberapa contoh penggunaannya.

Cara Kerja Lombok

Lombok bertindak sebagai pemroses anotasi yang “menambahkan” kode ke kelas Anda pada waktu kompilasi. Pemrosesan anotasi adalah fitur yang ditambahkan ke kompiler Java pada versi 5. Idenya adalah bahwa pengguna dapat menempatkan pemroses anotasi (ditulis oleh dirinya sendiri, atau melalui dependensi pihak ketiga, seperti Lombok) ke dalam classpath build. Kemudian, saat proses kompilasi berlangsung, setiap kali kompiler menemukan anotasi, ia akan bertanya: "Hei, siapa saja di classpath yang tertarik dengan @Annotation ini?." Untuk prosesor yang mengangkat tangan mereka, kompiler kemudian mentransfer kontrol kepada mereka bersama dengan konteks kompilasi untuk mereka, yah… proses.

Mungkin kasus paling umum untuk pemroses anotasi adalah membuat file sumber baru atau melakukan semacam pemeriksaan waktu kompilasi.

Lombok tidak termasuk dalam kategori berikut: Apa yang dilakukannya adalah memodifikasi struktur data kompiler yang digunakan untuk mewakili kode; yaitu, pohon sintaksis abstraknya (AST). Dengan memodifikasi AST kompiler, Lombok secara tidak langsung mengubah generasi bytecode terakhir itu sendiri.

Pendekatan yang tidak biasa dan agak mengganggu ini secara tradisional mengakibatkan Lombok dipandang sebagai peretasan. Sementara saya sendiri setuju dengan karakterisasi ini sampai batas tertentu, daripada melihat ini dalam arti kata yang buruk, saya akan melihat Lombok sebagai "alternatif yang cerdas, berjasa secara teknis, dan asli."

Namun, ada pengembang yang menganggapnya sebagai peretasan dan tidak menggunakan Lombok karena alasan ini. Itu bisa dimengerti, tetapi menurut pengalaman saya, manfaat produktivitas Lombok lebih besar daripada semua masalah ini. Saya telah dengan senang hati menggunakannya untuk proyek produksi selama bertahun-tahun sekarang.

Sebelum membahas detailnya, saya ingin merangkum dua alasan mengapa saya sangat menghargai penggunaan Lombok dalam proyek saya:

  1. Lombok membantu menjaga kode saya tetap bersih, ringkas, dan to the point. Saya menemukan kelas beranotasi Lombok saya sangat ekspresif dan saya biasanya menemukan kode beranotasi cukup mengungkapkan niat, meskipun tidak semua orang di internet harus setuju.
  2. Ketika saya memulai sebuah proyek dan memikirkan model domain, saya cenderung memulai dengan menulis kelas yang masih dalam proses dan saya mengubahnya secara berulang saat saya berpikir lebih jauh dan menyempurnakannya. Pada tahap awal ini, Lombok membantu saya bergerak lebih cepat dengan tidak perlu berpindah-pindah atau mengubah kode boilerplate yang dihasilkannya untuk saya.

Pola Kacang dan Metode Objek Umum

Banyak alat dan kerangka kerja Java yang kami gunakan bergantung pada Pola Kacang. Java Beans adalah kelas serial yang memiliki konstruktor zero-args default (dan mungkin versi lain) dan mengekspos statusnya melalui getter dan setter, biasanya didukung oleh bidang pribadi. Kami menulis banyak dari ini, misalnya ketika bekerja dengan JPA atau kerangka serialisasi seperti JAXB atau Jackson.

Pertimbangkan kacang Pengguna ini yang menampung hingga lima atribut (properti), di mana kami ingin memiliki konstruktor tambahan untuk semua atribut, representasi string yang bermakna, dan mendefinisikan kesetaraan/hashing dalam bidang emailnya:

 public class User implements Serializable { private String email; private String firstName; private String lastName; private Instant registrationTs; private boolean payingCustomer; // Empty constructor implementation: ~3 lines. // Utility constructor for all attributes: ~7 lines. // Getters/setters: ~38 lines. // equals() and hashCode() as per email: ~23 lines. // toString() for all attributes: ~3 lines. // Relevant: 5 lines; Boilerplate: 74 lines => 93% meaningless code :( }

Untuk singkatnya di sini, daripada memasukkan implementasi sebenarnya dari semua metode, saya malah hanya memberikan komentar yang mencantumkan metode dan jumlah baris kode yang diambil oleh implementasi aktual. Kode boilerplate itu akan berjumlah lebih dari 90% dari kode untuk kelas ini!

Selain itu, jika nanti saya ingin, katakanlah, mengubah email ke emailAddress atau registrationTs menjadi Date , bukan Instant , maka saya perlu mencurahkan waktu (dengan bantuan IDE saya untuk beberapa kasus, memang) untuk mengubah hal-hal seperti get /set nama dan tipe metode, ubah konstruktor utilitas saya, dan seterusnya. Sekali lagi, waktu yang tak ternilai untuk sesuatu yang tidak membawa nilai bisnis praktis ke kode saya.

Mari kita lihat bagaimana Lombok dapat membantu di sini:

 import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; @Getter @Setter @NoArgsConstructor @AllArgsConstructor @ToString @EqualsAndHashCode(of = {"email"}) public class User { private String email; private String firstName; private String lastName; private Instant registrationTs; private boolean payingCustomer; }

Voila! Saya baru saja menambahkan banyak anotasi lombok.* dan mencapai apa yang saya inginkan. Daftar di atas adalah persis semua kode yang saya perlukan untuk menulis ini. Lombok terhubung ke proses kompiler saya dan menghasilkan segalanya untuk saya (lihat tangkapan layar di bawah IDE saya).

Tangkapan Layar IDE

Seperti yang Anda perhatikan, inspektur NetBeans (dan ini akan terjadi terlepas dari IDE) mendeteksi bytecode kelas yang dikompilasi, termasuk tambahan yang dibawa Lombok ke dalam proses. Apa yang terjadi di sini cukup mudah:

  • Menggunakan @Getter dan @Setter saya menginstruksikan Lombok untuk menghasilkan getter dan setter untuk semua atribut. Ini karena saya menggunakan anotasi di tingkat kelas. Jika saya ingin secara selektif menentukan apa yang harus dihasilkan untuk atribut mana, saya dapat membuat anotasi pada bidang itu sendiri.
  • Terima kasih kepada @NoArgsConstructor dan @AllArgsConstructor , saya mendapatkan konstruktor kosong default untuk kelas saya serta tambahan untuk semua atribut.
  • Anotasi @ToString otomatis menghasilkan metode toString() yang praktis, menunjukkan secara default semua atribut kelas yang diawali dengan namanya.
  • Akhirnya, untuk memiliki pasangan metode equals() dan hashCode() yang didefinisikan dalam bidang email, saya menggunakan @EqualsAndHashCode dan membuat parameter dengan daftar bidang yang relevan (hanya email dalam kasus ini).

Menyesuaikan Anotasi Lombok

Sekarang mari kita gunakan beberapa kustomisasi Lombok mengikuti contoh yang sama ini:

  • Saya ingin menurunkan visibilitas konstruktor default. Karena saya hanya membutuhkannya untuk alasan kepatuhan kacang, saya berharap konsumen kelas hanya memanggil konstruktor yang mengambil semua bidang. Untuk menegakkan ini, saya menyesuaikan konstruktor yang dihasilkan dengan AccessLevel.PACKAGE .
  • Saya ingin memastikan bahwa bidang saya tidak pernah mendapatkan nilai nol yang ditetapkan, baik melalui konstruktor maupun melalui metode penyetel. Menganotasi atribut kelas dengan @NonNull sudah cukup; Lombok akan menghasilkan cek nol yang melempar NullPointerException bila sesuai dalam metode konstruktor dan penyetel.
  • Saya akan menambahkan atribut password , tetapi tidak ingin itu ditampilkan saat memanggil toString() untuk alasan keamanan. Ini dicapai melalui argumen pengecualian dari @ToString .
  • Saya baik-baik saja mengekspos keadaan secara publik melalui getter, tetapi lebih suka membatasi mutabilitas luar. Jadi saya membiarkan @Getter apa adanya, tetapi sekali lagi menggunakan AccessLevel.PROTECTED untuk @Setter .
  • Mungkin saya ingin memaksakan beberapa batasan pada bidang email sehingga, jika dimodifikasi, semacam pemeriksaan dijalankan. Untuk ini, saya hanya mengimplementasikan metode setEmail() sendiri. Lombok hanya akan menghilangkan generasi untuk metode yang sudah ada.

Beginilah tampilan kelas Pengguna:

 import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.Setter; import lombok.ToString; @Getter @Setter(AccessLevel.PROTECTED) @NoArgsConstructor(access = AccessLevel.PACKAGE) @AllArgsConstructor @ToString(exclude = {"password"}) @EqualsAndHashCode(of = {"email"}) public class User { private @NonNull String email; private @NonNull byte[] password; private @NonNull String firstName; private @NonNull String lastName; private @NonNull Instant registrationTs; private boolean payingCustomer; protected void setEmail(String email) { // Check for null (=> NullPointerException) // and valid email code (=> IllegalArgumentException) this.email = email; } }

Perhatikan bahwa, untuk beberapa anotasi, kami menetapkan atribut kelas sebagai string biasa. Tidak masalah, karena Lombok akan menimbulkan kesalahan kompilasi jika kita, misalnya, salah ketik atau merujuk ke bidang yang tidak ada. Dengan Lombok, kita aman.

Juga, seperti metode setEmail() , Lombok akan baik-baik saja dan tidak menghasilkan apa pun untuk metode yang telah diterapkan oleh programmer. Ini berlaku untuk semua metode dan konstruktor.

Struktur Data yang Tidak Dapat Diubah

Kasus penggunaan lain di mana Lombok unggul adalah saat membuat struktur data yang tidak dapat diubah. Ini biasanya disebut sebagai "tipe nilai." Beberapa bahasa memiliki dukungan bawaan untuk ini, dan bahkan ada proposal untuk memasukkan ini ke dalam versi Java yang akan datang.

Misalkan kita ingin memodelkan respons terhadap tindakan login pengguna. Ini adalah jenis objek yang ingin kita instantiate dan kembali ke lapisan lain dari aplikasi (misalnya, untuk menjadi serial JSON sebagai isi dari respons HTTP). LoginResponse seperti itu tidak perlu diubah sama sekali dan Lombok dapat membantu menjelaskan hal ini secara ringkas. Tentu, ada banyak kasus penggunaan lain untuk struktur data yang tidak dapat diubah (termasuk kualitas multithreading dan cache-friendly), tetapi mari kita tetap berpegang pada contoh sederhana ini:

 import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.ToString; import lombok.experimental.Wither; @Getter @RequiredArgsConstructor @ToString @EqualsAndHashCode public final class LoginResponse { private final long userId; private final @NonNull String authToken; private final @NonNull Instant loginTs; @Wither private final @NonNull Instant tokenExpiryTs; }

Perlu diperhatikan di sini:

  • Anotasi @RequiredArgsConstructor telah diperkenalkan. Dinamakan dengan tepat, apa yang dilakukannya adalah menghasilkan konstruktor untuk semua bidang akhir yang belum diinisialisasi.
  • Dalam kasus di mana kami ingin menggunakan kembali LoginResonse yang dikeluarkan sebelumnya (bayangkan, misalnya, operasi "token penyegaran"), kami tentu tidak ingin mengubah instance kami yang ada, melainkan, kami ingin membuat yang baru berdasarkan itu . Lihat bagaimana penjelasan @Wither membantu kita di sini: Ini memberitahu Lombok untuk menghasilkan metode withTokenExpiryTs(Instant tokenExpiryTs) yang membuat instance baru LoginResponse yang memiliki semua nilai instance with'ed, kecuali yang baru kita tentukan. Apakah Anda ingin perilaku ini untuk semua bidang? Cukup tambahkan @Wither ke deklarasi kelas.

@Data dan @Nilai

Kedua kasus penggunaan yang dibahas sejauh ini sangat umum sehingga Lombok mengirimkan beberapa anotasi untuk membuatnya lebih pendek: Memberi anotasi pada kelas dengan @Data akan memicu Lombok untuk berperilaku seolah-olah telah dianotasi dengan @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor . Demikian juga, menggunakan @Value akan mengubah kelas Anda menjadi kelas yang tidak dapat diubah (dan final), juga seolah-olah telah dijelaskan dengan daftar di atas.

Pola Pembangun

Kembali ke contoh Pengguna kami, jika kami ingin membuat instance baru, kami harus menggunakan konstruktor dengan hingga enam argumen. Ini sudah merupakan angka yang cukup besar, yang akan menjadi lebih buruk jika kita menambahkan atribut lebih lanjut ke kelas. Juga misalkan kita ingin menetapkan beberapa nilai default untuk bidang payingCustomer lastName

Lombok mengimplementasikan fitur @Builder yang sangat kuat, memungkinkan kami menggunakan Pola Builder untuk membuat instance baru. Mari tambahkan ke kelas Pengguna kami:

 import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.Setter; import lombok.ToString; @Getter @Setter(AccessLevel.PROTECTED) @NoArgsConstructor(access = AccessLevel.PACKAGE) @AllArgsConstructor @ToString(exclude = {"password"}) @EqualsAndHashCode(of = {"email"}) @Builder public class User { private @NonNull String email; private @NonNull byte[] password; private @NonNull String firstName; private @NonNull String lastName = ""; private @NonNull Instant registrationTs; private boolean payingCustomer = false; }

Sekarang kami dapat dengan lancar membuat pengguna baru seperti ini:

 User user = User .builder() .email("[email protected]") .password("secret".getBytes(StandardCharsets.UTF_8)) .firstName("Miguel") .registrationTs(Instant.now()) .build();

Sangat mudah untuk membayangkan betapa nyamannya konstruksi ini saat kelas kita tumbuh.

Delegasi/Komposisi

Jika Anda ingin mengikuti aturan yang sangat waras dari "mengutamakan komposisi daripada pewarisan" itu adalah sesuatu yang tidak terlalu membantu Java, dari segi verbositas. Jika Anda ingin membuat objek, Anda biasanya perlu menulis panggilan metode pendelegasian di semua tempat.

Lombok mengusulkan solusi untuk ini melalui @Delegate . Mari kita lihat sebuah contoh.

Bayangkan kita ingin memperkenalkan konsep baru dari ContactInformation . Ini adalah beberapa informasi yang dimiliki User kami dan kami mungkin ingin kelas lain juga memilikinya. Kami kemudian dapat memodelkan ini melalui antarmuka seperti ini:

 public interface HasContactInformation { String getEmail(); String getFirstName(); String getLastName(); }

Kami kemudian akan memperkenalkan kelas ContactInformation baru menggunakan Lombok:

 import lombok.Data; @Data public class ContactInformation implements HasContactInformation { private String email; private String firstName; private String lastName; }

Dan akhirnya, kami dapat memfaktorkan ulang User untuk menulis dengan ContactInformation dan menggunakan Lombok untuk menghasilkan semua panggilan delegasi yang diperlukan agar sesuai dengan kontrak antarmuka:

 import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.Setter; import lombok.ToString; import lombok.experimental.Delegate; @Getter @Setter(AccessLevel.PROTECTED) @NoArgsConstructor(access = AccessLevel.PACKAGE) @AllArgsConstructor @ToString(exclude = {"password"}) @EqualsAndHashCode(of = {"contactInformation"}) public class User implements HasContactInformation { @Getter(AccessLevel.NONE) @Delegate(types = {HasContactInformation.class}) private final ContactInformation contactInformation = new ContactInformation(); private @NonNull byte[] password; private @NonNull Instant registrationTs; private boolean payingCustomer = false; }

Perhatikan bagaimana saya tidak perlu menulis implementasi untuk metode HasContactInformation : ini adalah sesuatu yang kami ingin Lombok lakukan, mendelegasikan panggilan ke instance ContactInformation kami.

Juga, karena saya tidak ingin instance yang didelegasikan dapat diakses dari luar, saya menyesuaikannya dengan @Getter(AccessLevel.NONE) , yang secara efektif mencegah pembuatan getter untuknya.

Pengecualian yang Dicentang

Seperti yang kita semua tahu, Java membedakan antara pengecualian yang dicentang dan tidak dicentang. Ini adalah sumber tradisional untuk kontroversi dan kritik terhadap bahasa karena penanganan pengecualian terkadang terlalu banyak menghalangi kami, terutama ketika berurusan dengan API yang dirancang untuk membuang pengecualian yang diperiksa dan oleh karena itu memaksa kami pengembang untuk menangkapnya atau mendeklarasikan metode kami untuk membuang mereka.

Pertimbangkan contoh ini:

 public class UserService { public URL buildUsersApiUrl() { try { return new URL("https://apiserver.com/users"); } catch (MalformedURLException ex) { // Malformed? Really? throw new RuntimeException(ex); } } }

Ini adalah pola yang umum: Kami tentu tahu bahwa URL kami terbentuk dengan baik, namun—karena konstruktor URL melempar pengecualian yang dicentang—kami terpaksa menangkapnya atau mendeklarasikan metode kami untuk membuangnya dan mengeluarkan pemanggil dalam situasi yang sama. Membungkus pengecualian yang diperiksa ini di dalam RuntimeException adalah praktik yang sangat luas. Dan ini menjadi lebih buruk jika jumlah pengecualian yang diperiksa yang perlu kita tangani bertambah saat kita membuat kode.

Jadi inilah tepatnya @SneakyThrows Lombok, itu akan membungkus pengecualian yang dicentang untuk dilemparkan ke dalam metode kami menjadi yang tidak dicentang dan membebaskan kami dari kerumitan:

 import lombok.SneakyThrows; public class UserService { @SneakyThrows public URL buildUsersApiUrl() { return new URL("https://apiserver.com/users"); } }

Pencatatan

Seberapa sering Anda menambahkan instance logger ke kelas Anda seperti ini? (sampel SLF4J)

 private static final Logger LOG = LoggerFactory.getLogger(UserService.class);

Saya akan menebak sedikit. Mengetahui hal ini, pencipta Lombok menerapkan anotasi yang membuat instance logger dengan nama yang dapat disesuaikan (default untuk log), mendukung kerangka kerja logging paling umum di platform Java. Sama seperti ini (sekali lagi, berbasis SLF4J):

 import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @Slf4j public class UserService { @SneakyThrows public URL buildUsersApiUrl() { log.debug("Building users API URL"); return new URL("https://apiserver.com/users"); } }

Menganotasi Kode yang Dihasilkan

Jika kita menggunakan Lombok untuk menghasilkan kode, sepertinya kita akan kehilangan kemampuan untuk membubuhi keterangan metode tersebut karena kita tidak benar-benar menulisnya. Tapi ini tidak benar. Sebaliknya, Lombok memungkinkan kami untuk memberi tahu bagaimana kami ingin kode yang dihasilkan diberi anotasi, menggunakan notasi yang agak aneh, sejujurnya.

Pertimbangkan contoh ini, menargetkan penggunaan kerangka kerja injeksi ketergantungan: Kami memiliki kelas UserService yang menggunakan injeksi konstruktor untuk mendapatkan referensi ke UserRepository dan UserApiClient .

 package com.mgl.toptal.lombok; import javax.inject.Inject; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor(onConstructor = @__(@Inject)) public class UserService { private final UserRepository userRepository; private final UserApiClient userApiClient; // Instead of: // // @Inject // public UserService(UserRepository userRepository, // UserApiClient userApiClient) { // this.userRepository = userRepository; // this.userApiClient = userApiClient; // } }

Contoh di atas menunjukkan cara membuat anotasi pada konstruktor yang dihasilkan. Lombok memungkinkan kita untuk melakukan hal yang sama untuk metode dan parameter yang dihasilkan juga.

Belajar Lebih Banyak

Penggunaan Lombok yang dijelaskan dalam posting ini berfokus pada fitur-fitur yang menurut saya pribadi paling berguna selama bertahun-tahun. Namun, ada banyak fitur dan penyesuaian lain yang tersedia.

Dokumentasi Lombok sangat informatif dan menyeluruh. Mereka memiliki halaman khusus untuk setiap fitur (anotasi) dengan penjelasan dan contoh yang sangat rinci. Jika Anda menganggap posting ini menarik, saya mendorong Anda untuk menyelam lebih dalam ke lombok dan dokumentasinya untuk mengetahui lebih lanjut.

Situs proyek mendokumentasikan cara menggunakan Lombok di beberapa lingkungan pemrograman yang berbeda. Singkatnya, IDE paling populer (Eclipse, NetBeans dan IntelliJ) didukung. Saya sendiri secara teratur beralih dari satu ke yang lain berdasarkan proyek dan menggunakan Lombok pada semuanya dengan sempurna.

Delombok!

Delombok adalah bagian dari “Lombok toolchain” dan bisa sangat berguna. Apa yang dilakukannya pada dasarnya adalah menghasilkan kode sumber Java untuk kode beranotasi Lombok Anda, melakukan operasi yang sama dengan bytecode yang dihasilkan Lombok.

Ini adalah pilihan yang bagus untuk orang yang mempertimbangkan untuk mengadopsi Lombok tetapi belum yakin. Anda dapat dengan bebas mulai menggunakannya dan tidak akan ada "penguncian vendor". Jika Anda atau tim Anda kemudian menyesali pilihan tersebut, Anda selalu dapat menggunakan delombok untuk menghasilkan kode sumber yang sesuai yang kemudian dapat Anda gunakan tanpa ketergantungan yang tersisa pada Lombok.

Delombok juga merupakan alat yang hebat untuk mempelajari dengan tepat apa yang akan dilakukan Lombok. Ada cara yang sangat mudah untuk menghubungkannya ke dalam proses pembuatan Anda.

Alternatif

Ada banyak alat di dunia Java yang menggunakan prosesor anotasi serupa untuk memperkaya atau memodifikasi kode Anda pada waktu kompilasi, seperti Immutables atau Google Auto Value. Ini (dan lainnya, pasti!) tumpang tindih dengan fitur Lombok. Saya sangat menyukai pendekatan Immutables dan juga menggunakannya di beberapa proyek.

Perlu juga dicatat bahwa ada alat hebat lainnya yang menyediakan fitur serupa untuk "peningkatan bytecode", seperti Byte Buddy atau Javassist. Ini biasanya bekerja saat runtime, dan terdiri dari dunia mereka sendiri di luar cakupan posting ini.

Jawa ringkas

Ada sejumlah bahasa bertarget JVM modern yang menyediakan lebih banyak pendekatan desain idiomatik—atau bahkan tingkat bahasa—yang membantu mengatasi beberapa masalah yang sama. Tentunya Groovy, Scala, dan Kotlin adalah contoh yang bagus. Tetapi jika Anda mengerjakan proyek khusus Java, maka Lombok adalah alat yang bagus untuk membantu program Anda menjadi lebih ringkas, ekspresif, dan dapat dipelihara.

Terkait: Bahasa Dart: Ketika Java dan C# Tidak Cukup Tajam