اكتب كود جافا الخالي من الدهون مع مشروع لومبوك

نشرت: 2022-03-11

هناك عدد من الأدوات والمكتبات لا أستطيع تخيل نفسي أكتب كود Java بدون هذه الأيام. تقليديًا ، تعد أشياء مثل Google Guava أو Joda Time (على الأقل لعصر ما قبل Java 8) من بين التبعيات التي ينتهي بي الأمر بإلقاءها في مشاريعي معظم الوقت ، بغض النظر عن المجال المحدد في متناول اليد.

تستحق Lombok بالتأكيد مكانها في POMs أو Gradle أيضًا ، وإن لم تكن أداة مساعدة نموذجية للمكتبة / إطار العمل. كانت Lombok موجودة منذ فترة طويلة الآن (تم إصدارها لأول مرة في عام 2009) ونضجت كثيرًا منذ ذلك الحين. ومع ذلك ، فقد شعرت دائمًا أنها تستحق المزيد من الاهتمام - إنها طريقة رائعة للتعامل مع الإسهاب الطبيعي لجافا.

في هذا المنشور ، سوف نستكشف ما الذي يجعل Lombok أداة سهلة الاستخدام.

مشروع لومبوك

تحتوي Java على العديد من الأشياء التي تتعدى مجرد JVM نفسها ، والتي تعد جزءًا رائعًا من البرامج. جافا ناضجة وفعالة ، والمجتمع والنظام البيئي المحيط بها ضخمان وحيويان.

ومع ذلك ، كلغة برمجة ، تمتلك Java بعض الخصائص الخاصة بها بالإضافة إلى خيارات التصميم التي يمكن أن تجعلها مطولة إلى حد ما. أضف بعض التركيبات وأنماط الفئات التي غالبًا ما يحتاج مطورو Java لاستخدامها ، وكثيرًا ما ينتهي بنا المطاف بالعديد من أسطر التعليمات البرمجية التي تحقق القليل من القيمة الحقيقية أو لا تحقق أي قيمة حقيقية بخلاف الامتثال لمجموعة من القيود أو اصطلاحات إطار العمل.

هنا يأتي دور لومبوك. إنها تمكننا من تقليل كمية الكود "المعياري" الذي نحتاج إلى كتابته بشكل كبير. منشئو Lombok رجلان أذكياء جدًا ، ولهما بالتأكيد مذاق الفكاهة - لا يمكنك تفويت هذه المقدمة التي قدموها في مؤتمر سابق!

دعونا نرى كيف تقوم لومبوك بسحرها وبعض أمثلة الاستخدام.

كيف يعمل لومبوك

يعمل Lombok كمعالج للتعليقات التوضيحية "يضيف" رمزًا إلى فصولك الدراسية في وقت الترجمة. معالجة التعليقات التوضيحية هي ميزة تمت إضافتها إلى برنامج التحويل البرمجي Java في الإصدار 5. والفكرة هي أنه يمكن للمستخدمين وضع معالجات التعليقات التوضيحية (التي يكتبها الشخص بنفسه أو عن طريق تبعيات الطرف الثالث ، مثل Lombok) في مسار فئة الإنشاء. بعد ذلك ، أثناء استمرار عملية الترجمة ، كلما وجد المترجم تعليقًا توضيحيًا يسأل نوعًا ما: "مرحبًا ، أي شخص في مسار الفصل مهتم بهذا التعليق التوضيحي ؟." بالنسبة لأولئك المعالجات التي ترفع أيديهم ، يقوم المترجم بعد ذلك بنقل التحكم إليهم جنبًا إلى جنب مع سياق التجميع لهم من أجل ... معالجة جيدة.

ربما تكون الحالة الأكثر شيوعًا لمعالجات التعليقات التوضيحية هي إنشاء ملفات مصدر جديدة أو إجراء نوع من فحوصات وقت الترجمة.

Lombok لا تندرج حقًا في هذه الفئات: ما تفعله هو تعديل هياكل بيانات المترجم المستخدمة لتمثيل الكود ؛ أي شجرة التركيب المجردة (AST). من خلال تعديل AST للمترجم ، يقوم Lombok بشكل غير مباشر بتغيير الجيل الثانوي النهائي نفسه.

لقد أدى هذا النهج غير المعتاد والمتطفل إلى حد ما إلى اعتبار لومبوك نوعًا من الاختراق. على الرغم من أنني أتفق مع هذا التوصيف إلى حد ما ، بدلاً من النظر إلى هذا بالمعنى السيئ للكلمة ، فإنني أرى لومبوك على أنه "بديل ذكي وجدير بالتقدير من الناحية الفنية."

ومع ذلك ، هناك مطورو يعتبرونه اختراقًا ولا يستخدمون Lombok لهذا السبب. هذا أمر مفهوم ، ولكن من واقع خبرتي ، فإن فوائد الإنتاجية في لومبوك تفوق أيًا من هذه المخاوف. لقد كنت أستخدمه بسعادة في مشاريع الإنتاج لسنوات عديدة حتى الآن.

قبل الخوض في التفاصيل ، أود أن ألخص السببين اللذين أقدّر بشكل خاص استخدام لومبوك في مشاريعي:

  1. تساعد Lombok في الحفاظ على الكود الخاص بي نظيفًا وموجزًا ​​ومباشرًا. أجد فصول Lombok المشروحة معبرة جدًا وأجد عمومًا أن الشفرة المشروحة تكشف عن النية تمامًا ، على الرغم من عدم موافقة الجميع على الإنترنت بالضرورة.
  2. عندما أبدأ مشروعًا وأفكر في نموذج مجال ، أميل إلى البدء بكتابة فصول دراسية هي عمل مستمر إلى حد كبير وأنني أغيرها بشكل تكراري كما أفكر أكثر وصقلها. في هذه المراحل المبكرة ، يساعدني Lombok على التحرك بشكل أسرع من خلال عدم الحاجة إلى التحرك أو تحويل الكود المعياري الذي ينشئه لي.

نمط الفول وطرق الكائنات الشائعة

تعتمد العديد من أدوات وأطر عمل Java التي نستخدمها على نمط Bean. Java Beans عبارة عن فئات قابلة للتسلسل تحتوي على مُنشئ افتراضي ذي قيمة صفرية (وربما إصدارات أخرى) وتكشف عن حالتها عبر أدوات الاستيعاب والمستوطنين ، وعادةً ما تكون مدعومة بحقول خاصة. نكتب الكثير منها ، على سبيل المثال عند العمل مع JPA أو أطر التسلسل مثل JAXB أو Jackson.

ضع في اعتبارك وحدة المستخدم هذه التي تحتوي على ما يصل إلى خمس سمات (خصائص) ، والتي نود أن يكون لها مُنشئ إضافي لجميع السمات ، وتمثيل سلسلة ذي معنى ، وتعريف المساواة / التجزئة من حيث حقل البريد الإلكتروني الخاص بها:

 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 :( }

للإيجاز هنا ، بدلاً من تضمين التنفيذ الفعلي لجميع الطرق ، فقد قدمت بدلاً من ذلك تعليقات تسرد الطرق وعدد سطور الكود التي استغرقتها عمليات التنفيذ الفعلية. كان من الممكن أن يصل إجمالي الشفرة المعيارية إلى أكثر من 90٪ من رمز هذه الفئة!

علاوة على ذلك ، إذا أردت لاحقًا ، على سبيل المثال ، تغيير email إلى emailAddress البريد الإلكتروني أو جعل registrationTs عبارة عن Date بدلاً من Instant ، فأنا بحاجة إلى تخصيص وقت (بمساعدة IDE الخاص بي في بعض الحالات ، باعتراف الجميع) لتغيير أشياء مثل الحصول / تعيين أسماء الطرق وأنواعها ، وتعديل مُنشئ الأداة المساعدة الخاص بي ، وما إلى ذلك. مرة أخرى ، وقت لا يقدر بثمن لشيء لا يجلب أي قيمة عملية عملية إلى الكود الخاص بي.

دعونا نرى كيف يمكن أن تساعد لومبوك هنا:

 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; }

هاهو! لقد أضفت للتو مجموعة من تعليقات lombok.* وحققت ما أردت. القائمة أعلاه هي بالضبط كل الكود الذي أحتاج إلى كتابته لهذا الغرض. يقوم Lombok بالربط في عملية المترجم الخاص بي وإنشاء كل شيء لي (انظر لقطة الشاشة أدناه من IDE الخاص بي).

لقطة شاشة IDE

كما لاحظت ، يقوم مفتش NetBeans (وهذا سيحدث بغض النظر عن IDE) بالكشف عن رمز بايت للفئة المترجمة ، بما في ذلك الإضافات التي أدخلها Lombok في العملية. ما حدث هنا واضح تمامًا:

  • باستخدام @Getter و @Setter ، أصدرت تعليمات إلى Lombok لتوليد محصلات وضوابط لجميع السمات. هذا لأنني استخدمت التعليقات التوضيحية على مستوى الفصل. إذا كنت أرغب في تحديد ما يجب إنشاؤه من أجل أي سمات بشكل انتقائي ، كان بإمكاني وضع تعليق توضيحي على الحقول نفسها.
  • بفضل @NoArgsConstructor و @AllArgsConstructor ، حصلت على مُنشئ افتراضي فارغ لفصلي بالإضافة إلى مُنشئ إضافي لجميع السمات.
  • ينشئ التعليق التوضيحي @ToString تلقائيًا طريقة toString() سهلة الاستخدام ، تعرض افتراضيًا جميع سمات الفئة مسبوقة بأسمائها.
  • أخيرًا ، للحصول على زوج من أساليب equals() و hashCode() المحددة من حيث حقل البريد الإلكتروني ، استخدمت @EqualsAndHashCode وقمت بوضع معلمات لها مع قائمة الحقول ذات الصلة (فقط البريد الإلكتروني في هذه الحالة).

تخصيص شروح لومبوك

دعنا الآن نستخدم بعض تخصيصات Lombok باتباع نفس المثال:

  • أرغب في تقليل رؤية المُنشئ الافتراضي. نظرًا لأنني أحتاجه فقط لأسباب توافق الفول ، أتوقع أن يتصل مستهلكو الفصل فقط بالمُنشئ الذي يأخذ جميع المجالات. لفرض ذلك ، أقوم بتخصيص المُنشئ المُنشأ باستخدام AccessLevel.PACKAGE .
  • أريد التأكد من عدم تعيين قيم فارغة لحقولي ، لا من خلال المنشئ ولا عبر طرق التعيين. يعد التعليق التوضيحي لسمات الفئة باستخدام @NonNull كافيًا ؛ ستُنشئ Lombok عمليات تحقق فارغة NullPointerException عندما يكون ذلك مناسبًا في طرق المُنشئ والمُحدِّد.
  • سأضيف سمة password ، لكنني لا أريدها أن تظهر عند استدعاء toString() لأسباب أمنية. يتم تحقيق ذلك من خلال وسيطة الاستثناءات الخاصة بـ @ToString .
  • أنا على ما يرام في تعريض الحالة علنًا عبر أدوات الإلمام ، لكني أفضل تقييد قابلية التغيير الخارجية. لذلك @Getter كما هو ، ولكن مرة أخرى باستخدام AccessLevel.PROTECTED لـ @Setter .
  • ربما أرغب في فرض بعض القيود على حقل email بحيث إذا تم تعديله ، يتم إجراء نوع من الفحص. لهذا ، قمت فقط بتنفيذ طريقة setEmail() بنفسي. سوف يتجاهل لومبوك التوليد لطريقة موجودة بالفعل.

هذه هي الطريقة التي ستبدو عليها فئة المستخدم بعد ذلك:

 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; } }

لاحظ أنه بالنسبة لبعض التعليقات التوضيحية ، فإننا نحدد سمات الفئة كسلاسل عادية. ليست مشكلة ، لأن لومبوك سيرمي خطأ تجميع إذا ، على سبيل المثال ، أخطأنا في الكتابة أو أشرنا إلى حقل غير موجود. مع لومبوك ، نحن بأمان.

أيضًا ، تمامًا مثل طريقة setEmail() ، سيكون Lombok على ما يرام ولن يُنشئ أي شيء لطريقة نفذها المبرمج بالفعل. هذا ينطبق على جميع الأساليب والمنشئات.

هياكل البيانات غير القابلة للتغيير

حالة استخدام أخرى حيث تتفوق لومبوك هي عند إنشاء هياكل بيانات غير قابلة للتغيير. يُشار إلى هذه عادةً باسم "أنواع القيم". تحتوي بعض اللغات على دعم مدمج لها ، وهناك أيضًا اقتراح لدمج هذا في إصدارات Java المستقبلية.

لنفترض أننا نريد أن نصمم استجابة لإجراء تسجيل دخول المستخدم. هذا هو نوع الكائن الذي نريد فقط إنشاء مثيل له والعودة إلى طبقات أخرى من التطبيق (على سبيل المثال ، أن يتم تسلسل JSON باعتباره نص استجابة HTTP). لن يحتاج مثل هذا LoginResponse إلى أن يكون قابلاً للتغيير على الإطلاق ويمكن أن تساعد Lombok في وصف ذلك بإيجاز. بالتأكيد ، هناك العديد من حالات الاستخدام الأخرى لهياكل البيانات غير القابلة للتغيير (فهي متعددة مؤشرات الترابط - وذاكرة التخزين المؤقت ، من بين الصفات الأخرى) ، ولكن دعنا نلتزم بهذا المثال البسيط:

 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; }

جدير بالذكر هنا:

  • تم تقديم تعليق توضيحي @RequiredArgsConstructor . يسمى بشكل مناسب ، ما يفعله هو إنشاء مُنشئ لجميع الحقول النهائية التي لم تتم تهيئتها بالفعل.
  • في الحالات التي نريد فيها إعادة استخدام تسجيل الدخول الذي تم إصداره مسبقًا (تخيل ، على سبيل المثال ، عملية "تحديث الرمز المميز") ، لا نريد بالتأكيد تعديل مثيلنا الحالي ، ولكن بدلاً من ذلك ، نريد إنشاء مثيل جديد بناءً عليه . شاهد كيف يساعدنا التعليق التوضيحي @Wither هنا: إنه يخبر لومبوك بإنشاء طريقة withTokenExpiryTs(Instant tokenExpiryTs) التي تنشئ مثيلًا جديدًا من LoginResponse يحتوي على جميع قيم المثيلات with'ed ، باستثناء القيمة الجديدة التي نحددها. هل تحب هذا السلوك لجميع المجالات؟ ما عليك سوى إضافة @Wither إلى إعلان الفئة بدلاً من ذلك.

@ البيانات و @ القيمة

حالتا الاستخدام اللتان تمت مناقشتهما حتى الآن شائعتان للغاية لدرجة أن Lombok تقوم بشحن بضع تعليقات توضيحية لجعلها أقصر: سيؤدي التعليق التوضيحي للفصل باستخدام @Data إلى جعل Lombok تتصرف تمامًا كما لو تم التعليق عليها باستخدام @Getter + @Setter + @ToString + @EqualsAndHashCode @RequiredArgsConstructor وبالمثل ، سيؤدي استخدام @Value إلى تحويل فصلك الدراسي إلى فصل دراسي غير قابل للتغيير (ونهائي) ، أيضًا مرة أخرى كما لو تم التعليق عليه بالقائمة أعلاه.

نمط البناء

بالعودة إلى مثال المستخدم الخاص بنا ، إذا أردنا إنشاء مثيل جديد ، فسنحتاج إلى استخدام مُنشئ مع ما يصل إلى ست وسائط. هذا بالفعل رقم كبير إلى حد ما ، وسيزداد سوءًا إذا أضفنا سمات إلى الفصل. لنفترض أيضًا أننا نرغب في تعيين بعض القيم الافتراضية lastName payingCustomer .

يطبق Lombok ميزة @Builder قوية جدًا ، مما يسمح لنا باستخدام نموذج Builder لإنشاء مثيلات جديدة. دعنا نضيفه إلى فئة المستخدم لدينا:

 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; }

الآن نحن قادرون على إنشاء مستخدمين جدد بطلاقة مثل هذا:

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

من السهل تخيل مدى ملاءمة هذا البناء مع نمو فصولنا.

التفويض / التكوين

إذا كنت ترغب في اتباع القاعدة العقلانية "تفضيل التكوين على الميراث" فهذا شيء لا تساعده Java حقًا ، من الحكمة الإسهاب. إذا كنت ترغب في إنشاء كائنات ، فستحتاج عادةً إلى كتابة استدعاءات طريقة التفويض في كل مكان.

يقترح لومبوك حلاً لذلك عبر @Delegate . دعنا نلقي نظرة على مثال.

تخيل أننا نريد تقديم مفهوم جديد ContactInformation . هذه بعض المعلومات التي يمتلكها User وقد نرغب في الحصول على فصول أخرى أيضًا. يمكننا بعد ذلك نمذجة هذا عبر واجهة مثل هذه:

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

سنقدم بعد ذلك فئة ContactInformation جديدة باستخدام Lombok:

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

وأخيرًا ، يمكننا إعادة تشكيل User لإنشاء ContactInformation واستخدام Lombok لإنشاء جميع استدعاءات التفويض المطلوبة لمطابقة عقد الواجهة:

 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; }

لاحظ كيف لم أكن بحاجة إلى كتابة تطبيقات لأساليب HasContactInformation : هذا شيء نطلب من Lombok القيام به ، وتفويض المكالمات إلى مثيل ContactInformation الخاص بنا.

أيضًا ، نظرًا لأنني لا أريد أن يكون المثيل المفوض متاحًا من الخارج ، فأنا أقوم بتخصيصه باستخدام @Getter(AccessLevel.NONE) ، مما يمنع بشكل فعال إنشاء برنامج getter له.

الاستثناءات المحددة

كما نعلم جميعًا ، تميز Java بين الاستثناءات المحددة وغير المحددة. يعد هذا مصدرًا تقليديًا للجدل والنقد للغة نظرًا لأن معالجة الاستثناءات أحيانًا ما تعترض طريقنا كثيرًا نتيجة لذلك ، خاصةً عند التعامل مع واجهات برمجة التطبيقات المصممة لإلقاء الاستثناءات المحددة وبالتالي إجبارنا المطورين على الإمساك بها أو الإعلان عن أساليبنا رمى بها.

ضع في اعتبارك هذا المثال:

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

هذا نمط شائع: نحن نعلم بالتأكيد أن عنوان URL الخاص بنا قد تم تشكيله جيدًا ، ومع ذلك - نظرًا لأن مُنشئ URL يطرح استثناءًا محددًا - إما أننا مجبرون على الإمساك به أو الإعلان عن طريقتنا في التخلص منه وإخراج المتصلين في نفس الموقف. يعد التفاف هذه الاستثناءات المحددة داخل RuntimeException ممارسة ممتدة للغاية. ويزداد هذا الأمر سوءًا إذا زاد عدد الاستثناءات المحددة التي نحتاج إلى التعامل معها أثناء قيامنا بالبرمجة.

إذن ، هذا هو بالضبط ما @SneakyThrows ، فإنه سوف يلتف أي استثناءات محددة تخضع لإلقائها في طريقتنا في طريقة غير محددة وتحررنا من المتاعب:

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

تسجيل

كم مرة تضيف مثيلات المسجل إلى فصولك الدراسية مثل هذا؟ (عينة SLF4J)

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

سأخمن قليلا. مع العلم بذلك ، قام منشئو Lombok بتنفيذ تعليق توضيحي يقوم بإنشاء مثيل مسجل باسم قابل للتخصيص (افتراضيًا للتسجيل) ، مما يدعم أكثر أطر التسجيل شيوعًا على نظام Java الأساسي. تمامًا مثل هذا (مرة أخرى ، يعتمد على 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"); } }

شرح التعليمات البرمجية التي تم إنشاؤها

إذا استخدمنا Lombok لإنشاء رمز ، فقد يبدو أننا نفقد القدرة على إضافة تعليقات توضيحية إلى هذه الأساليب لأننا لا نكتبها بالفعل. لكن هذا ليس صحيحًا حقًا. بدلاً من ذلك ، تسمح لنا لومبوك بإخبارها كيف نرغب في وضع تعليقات توضيحية على الكود المُنشأ ، باستخدام تدوين غريب إلى حد ما ، ولكن الحقيقة تُقال.

ضع في اعتبارك هذا المثال ، الذي يستهدف استخدام إطار عمل حقن التبعية: لدينا فئة UserService تستخدم حقن المُنشئ للحصول على المراجع إلى UserRepository و 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; // } }

يوضح النموذج أعلاه كيفية إضافة تعليق توضيحي على مُنشئ تم إنشاؤه. يسمح لنا لومبوك بفعل الشيء نفسه بالنسبة للطرق والمعلمات المُنشأة أيضًا.

تعلم المزيد

يركز استخدام Lombok الموضح في هذا المنشور على تلك الميزات التي وجدتها شخصيًا أكثر فائدة على مر السنين. ومع ذلك ، هناك العديد من الميزات والتخصيصات الأخرى المتاحة.

وثائق لومبوك غنية بالمعلومات وشاملة. لقد خصصوا صفحات لكل ميزة (تعليق توضيحي) مع شروحات وأمثلة مفصلة للغاية. إذا وجدت هذا المنشور مثيرًا للاهتمام ، فأنا أشجعك على التعمق في لومبوك ووثائقها لمعرفة المزيد.

يوثق موقع المشروع كيفية استخدام Lombok في عدة بيئات برمجة مختلفة. باختصار ، يتم دعم IDEs الأكثر شيوعًا (Eclipse و NetBeans و IntelliJ). أنا بنفسي أنتقل بانتظام من واحد إلى آخر على أساس كل مشروع وأستخدم Lombok على كل منهم بلا عيب.

ديلومبوك!

Delombok هو جزء من "Lombok toolchain" ويمكن أن يكون مفيدًا جدًا. ما يفعله هو في الأساس إنشاء كود مصدر Java لكود Lombok المشروح الخاص بك ، وتنفيذ نفس العمليات التي يقوم بها Lombok الذي تم إنشاؤه بواسطة الرمز الثانوي.

يعد هذا خيارًا رائعًا للأشخاص الذين يفكرون في تبني لومبوك ولكنهم غير متأكدين تمامًا بعد. يمكنك البدء في استخدامه بحرية ولن يكون هناك "حجز للبائع". في حال ندمت أنت أو فريقك لاحقًا على هذا الاختيار ، يمكنك دائمًا استخدام delombok لإنشاء كود المصدر المقابل الذي يمكنك استخدامه بعد ذلك دون أي تبعية متبقية على Lombok.

تعد Delombok أيضًا أداة رائعة لمعرفة ما ستفعله Lombok بالضبط. هناك طرق سهلة للغاية لإدخالها في عملية الإنشاء الخاصة بك.

البدائل

هناك العديد من الأدوات في عالم Java تستخدم معالجات التعليقات التوضيحية بشكل مماثل لإثراء أو تعديل التعليمات البرمجية الخاصة بك في وقت الترجمة ، مثل العناصر الثابتة أو قيمة Google التلقائية. هذه (وغيرها ، بالتأكيد!) تتداخل مع ميزة لومبوك. يعجبني بشكل خاص نهج العناصر الثابتة كثيرًا وقد استخدمته أيضًا في بعض المشاريع.

تجدر الإشارة أيضًا إلى أن هناك أدوات رائعة أخرى توفر ميزات مماثلة لـ "تحسين الرمز الثنائي" ، مثل Byte Buddy أو Javassist. تعمل هذه عادةً في وقت التشغيل على الرغم من ذلك ، وتشكل عالماً خاصاً بها خارج نطاق هذا المنشور.

جافا موجزة

هناك عدد من لغات JVM المستهدفة الحديثة التي توفر أساليب تصميم أكثر اصطلاحية - أو حتى مستوى لغوي - تساعد في معالجة بعض نفس المشكلات. من المؤكد أن Groovy و Scala و Kotlin أمثلة جيدة. ولكن إذا كنت تعمل في مشروع Java فقط ، فإن Lombok هي أداة رائعة لمساعدة برامجك على أن تكون أكثر إيجازًا وتعبيرًا وقابلية للصيانة.

الموضوعات ذات الصلة: لغة Dart: عندما لا تكون Java و C # شاربين بدرجة كافية