ملاحظة : أعمل على الإصدار 2 من هذا الدليل وأحتاج إلى مساعدتك! الرجاء استخدام هذا النموذج لإعطائي تعليقات حول ما تعتقد أنه يجب أن يتم تضمينه في الإصدار التالي. شكرًا!
تعد Java واحدة من أكثر لغات البرمجة شيوعًا، ولكن لا يبدو أن أحدًا يستمتع باستخدامها. حسنًا، Java هي في الواقع لغة برمجة جيدة، ومنذ ظهور Java 8 مؤخرًا، قررت تجميع قائمة من المكتبات والممارسات والأدوات لجعل استخدام Java أفضل. "الأفضل" أمر شخصي، لذا أوصي بأخذ الأجزاء التي تتحدث إليك واستخدامها، بدلاً من محاولة استخدامها جميعًا مرة واحدة. لا تتردد في تقديم طلبات السحب التي تقترح الإضافات.
تم نشر هذه المقالة في الأصل على مدونتي.
اقرأ هذا بلغات أخرى: الإنجليزية، 简体中文
تقليديًا، تمت برمجة Java بأسلوب JavaBean المؤسسي المطول للغاية. النمط الجديد أكثر نظافة وصحة وأسهل على العيون.
أحد أبسط الأشياء التي نقوم بها كمبرمجين هو تمرير البيانات. الطريقة التقليدية للقيام بذلك هي تعريف JavaBean:
public class DataHolder {
private String data ;
public DataHolder () {
}
public void setData ( String data ) {
this . data = data ;
}
public String getData () {
return this . data ;
}
}
وهذا إسراف وإسراف. حتى لو قام IDE الخاص بك بإنشاء هذا الرمز تلقائيًا، فهذا مضيعة. لذا، لا تفعل هذا.
بدلاً من ذلك، أفضّل أسلوب البنية C لكتابة الفئات التي تحتوي فقط على البيانات:
public class DataHolder {
public final String data ;
public DataHolder ( String data ) {
this . data = data ;
}
}
وهذا يعني تقليل عدد أسطر التعليمات البرمجية بمقدار النصف. علاوة على ذلك، هذه الفئة غير قابلة للتغيير إلا إذا قمت بتوسيعها، لذلك يمكننا التفكير فيها بشكل أسهل لأننا نعلم أنه لا يمكن تغييرها.
إذا كنت تقوم بتخزين كائنات مثل Map أو List التي يمكن تعديلها بسهولة، فيجب عليك بدلاً من ذلك استخدام ImmutableMap أو ImmutableList، والتي تمت مناقشتها في القسم الخاص بالثبات.
إذا كان لديك كائن معقد نوعًا ما وتريد إنشاء هيكل له، ففكر في نمط الباني.
يمكنك إنشاء فئة داخلية ثابتة والتي ستقوم ببناء الكائن الخاص بك. يستخدم حالة قابلة للتغيير، ولكن بمجرد استدعاء البناء، فإنه سيصدر كائنًا غير قابل للتغيير.
تخيل أن لدينا DataHolder أكثر تعقيدًا. قد يبدو منشئه كما يلي:
public class ComplicatedDataHolder {
public final String data ;
public final int num ;
// lots more fields and a constructor
public static class Builder {
private String data ;
private int num ;
public Builder data ( String data ) {
this . data = data ;
return this ;
}
public Builder num ( int num ) {
this . num = num ;
return this ;
}
public ComplicatedDataHolder build () {
return new ComplicatedDataHolder ( data , num ); // etc
}
}
}
ثم لاستخدامه:
final ComplicatedDataHolder cdh = new ComplicatedDataHolder . Builder ()
. data ( "set this" )
. num ( 523 )
. build ();
هناك أمثلة أفضل للبناة في أماكن أخرى ولكن هذا من شأنه أن يمنحك فكرة عما يبدو عليه الأمر. ينتهي هذا بالكثير من النموذج النمطي الذي كنا نحاول تجنبه، ولكنه يوفر لك كائنات غير قابلة للتغيير وواجهة سلسة للغاية.
بدلاً من إنشاء كائنات البناء يدويًا، فكر في استخدام إحدى المكتبات العديدة التي يمكن أن تساعدك في إنشاء كائنات البناء.
إذا قمت بإنشاء العديد من الكائنات غير القابلة للتغيير يدويًا، ففكر في استخدام معالج التعليقات التوضيحية لإنشاءها من الواجهات تلقائيًا. وهذا يقلل من التعليمات البرمجية المعيارية، ويقلل من احتمالية الأخطاء ويعزز الثبات. راجع هذا العرض التقديمي للحصول على مناقشة مثيرة للاهتمام حول بعض المشكلات المتعلقة بأنماط ترميز Java العادية.
بعض مكتبات توليد الأكواد الرائعة هي مكتبات غير قابلة للتغيير، وقيمة Google التلقائية وLombok.
يجب استخدام الاستثناءات المحددة بحذر، على كل حال. إنهم يجبرون المستخدمين على إضافة العديد من كتل المحاولة/الالتقاط والتفاف الاستثناءات الخاصة بهم. الأفضل هو جعل الاستثناءات الخاصة بك تمتد إلى RuntimeException بدلاً من ذلك. يتيح ذلك للمستخدمين التعامل مع الاستثناءات الخاصة بك بالطريقة التي يريدونها، بدلاً من إجبارهم على التعامل/الإعلان عن أنها تطرح في كل مرة، مما يلوث الكود.
إحدى الحيل الرائعة هي وضع RuntimeExceptions في إعلان رميات طريقتك. ليس لهذا أي تأثير على المترجم، لكنه سيُعلم المستخدمين من خلال الوثائق بإمكانية طرح هذه الاستثناءات.
يعد هذا قسمًا لهندسة البرمجيات أكثر من كونه قسمًا لـ Java، ولكن إحدى أفضل الطرق لكتابة برامج قابلة للاختبار هي استخدام حقن التبعية (DI). لأن Java تشجع بقوة تصميم OO، لإنشاء برامج قابلة للاختبار، تحتاج إلى استخدام DI.
في Java، يتم ذلك عادةً باستخدام Spring Framework. يحتوي إما على أسلاك تعتمد على التعليمات البرمجية أو أسلاك تعتمد على تكوين XML. إذا كنت تستخدم تكوين XML، فمن المهم عدم الإفراط في استخدام Spring بسبب تنسيق التكوين المستند إلى XML. يجب ألا يكون هناك أي هياكل منطقية أو تحكم على الإطلاق في XML. يجب أن يحقن التبعيات فقط.
من البدائل الجيدة لاستخدام Spring مكتبة Google وSquare's Dagger أو Google's Guice. إنهم لا يستخدمون تنسيق ملف تكوين XML الخاص بـ Spring، وبدلاً من ذلك يضعون منطق الإدخال في التعليقات التوضيحية وفي التعليمات البرمجية.
حاول تجنب استخدام القيم الخالية عندما تستطيع. لا تقم بإرجاع مجموعات فارغة عندما كان يجب عليك بدلاً من ذلك إرجاع مجموعة فارغة. إذا كنت ستستخدم القيمة null، ففكر في التعليق التوضيحي @Nullable. يحتوي IntelliJ IDEA على دعم مدمج للتعليق التوضيحي @Nullable.
اقرأ المزيد عن سبب عدم استخدام القيم الخالية في أسوأ خطأ في علوم الكمبيوتر.
إذا كنت تستخدم Java 8، فيمكنك استخدام النوع الاختياري الجديد الممتاز. إذا كانت هناك قيمة موجودة أو غير موجودة، فقم بتغليفها في فئة اختيارية مثل هذا:
public class FooWidget {
private final String data ;
private final Optional < Bar > bar ;
public FooWidget ( String data ) {
this ( data , Optional . empty ());
}
public FooWidget ( String data , Optional < Bar > bar ) {
this . data = data ;
this . bar = bar ;
}
public Optional < Bar > getBar () {
return bar ;
}
}
من الواضح الآن أن البيانات لن تكون فارغة أبدًا، ولكن قد يكون الشريط موجودًا أو لا يكون موجودًا. يحتوي الخيار الاختياري على أساليب مثل isPresent ، مما قد يجعل الأمر يبدو وكأنه لا يختلف كثيرًا عن مجرد التحقق من القيمة null . لكنه يسمح لك بكتابة عبارات مثل:
final Optional < FooWidget > fooWidget = maybeGetFooWidget ();
final Baz baz = fooWidget . flatMap ( FooWidget :: getBar )
. flatMap ( BarWidget :: getBaz )
. orElse ( defaultBaz );
وهو أفضل بكثير من بالسلاسل إذا كانت الشيكات فارغة. الجانب السلبي الوحيد لاستخدام اختياري هو أن المكتبة القياسية لا تتمتع بدعم اختياري جيد، لذلك لا يزال التعامل مع القيم الخالية مطلوبًا هناك.
ما لم يكن لديك سبب وجيه لجعلها مختلفة، يجب أن تكون المتغيرات والفئات والمجموعات غير قابلة للتغيير.
يمكن جعل المتغيرات غير قابلة للتغيير باستخدام Final :
final FooWidget fooWidget ;
if ( condition ()) {
fooWidget = getWidget ();
} else {
try {
fooWidget = cachedFooWidget . get ();
} catch ( CachingException e ) {
log . error ( "Couldn't get cached value" , e );
throw e ;
}
}
// fooWidget is guaranteed to be set here
الآن يمكنك التأكد من أنه لن يتم إعادة تعيين fooWidget عن طريق الخطأ. تعمل الكلمة الأساسية النهائية مع كتل if/else ومع كتل Try/catch. بالطبع، إذا لم يكن fooWidget نفسه غير قابل للتغيير، فيمكنك تعديله بسهولة.
يجب أن تستخدم المجموعات، كلما أمكن ذلك، فئات Guava ImmutableMap أو ImmutableList أو ImmutableSet. تحتوي هذه العناصر على أدوات إنشاء بحيث يمكنك بنائها ديناميكيًا ومن ثم وضع علامة عليها باعتبارها غير قابلة للتغيير عن طريق استدعاء طريقة الإنشاء.
يجب أن تكون الفئات غير قابلة للتغيير من خلال الإعلان عن الحقول غير القابلة للتغيير (عبر Final ) وباستخدام المجموعات غير القابلة للتغيير. اختياريًا، يمكنك جعل الفصل نفسه نهائيًا بحيث لا يمكن تمديده وجعله قابلاً للتغيير.
كن حذرًا إذا وجدت نفسك تضيف الكثير من الأساليب إلى فئة Util.
public class MiscUtil {
public static String frobnicateString ( String base , int times ) {
// ... etc
}
public static void throwIfCondition ( boolean condition , String msg ) {
// ... etc
}
}
تبدو هذه الفئات، في البداية، جذابة لأن الأساليب المتبعة فيها لا تنتمي حقًا إلى مكان واحد. لذلك قمت بإلقاء كل منهم هنا باسم إعادة استخدام التعليمات البرمجية.
فالعلاج أسوأ من المرض. ضع هذه الفئات في مكانها المناسب وأعد البناء بقوة. لا تقم بتسمية الفئات أو الحزم أو المكتبات بأي شيء عام للغاية، مثل "MiscUtils" أو "ExtrasLibrary". وهذا يشجع على إلقاء التعليمات البرمجية غير ذات الصلة هناك.
يعد التنسيق أقل أهمية بكثير مما يتصوره معظم المبرمجين. هل يُظهر الاتساق أنك تهتم بمهنتك وهل يساعد الآخرين على القراءة؟ قطعاً. ولكن دعونا لا نضيع يومًا في إضافة مسافات إلى الكتل بحيث "تتطابق".
إذا كنت بحاجة ماسة إلى دليل تنسيق التعليمات البرمجية، فإنني أوصي بشدة بدليل Java Style من Google. أفضل جزء من هذا الدليل هو قسم ممارسات البرمجة. بالتأكيد تستحق القراءة.
يعد توثيق الكود الذي يواجه المستخدم أمرًا مهمًا. وهذا يعني استخدام الأمثلة واستخدام الأوصاف المعقولة للمتغيرات والأساليب والفئات.
والنتيجة الطبيعية لذلك هي عدم توثيق ما لا يحتاج إلى توثيق. إذا لم يكن لديك ما تقوله حول ماهية الحجة، أو إذا كانت واضحة، فلا تقم بتوثيقها. يعد التوثيق النموذجي أسوأ من عدم وجود أي توثيق على الإطلاق، لأنه يخدع المستخدمين لديك للاعتقاد بوجود توثيق.
يحتوي Java 8 على دفق جيد وبناء جملة لامدا. يمكنك كتابة كود مثل هذا:
final List < String > filtered = list . stream ()
. filter ( s -> s . startsWith ( "s" ))
. map ( s -> s . toUpperCase ())
. collect ( Collectors . toList ());
بدلا من هذا:
final List < String > filtered = new ArrayList <>();
for ( String str : list ) {
if ( str . startsWith ( "s" ) {
filtered . add ( str . toUpperCase ());
}
}
يتيح لك ذلك كتابة تعليمات برمجية أكثر طلاقة، مما يجعلها أكثر قابلية للقراءة.
قد يكون نشر Java بشكل صحيح أمرًا صعبًا بعض الشيء. هناك طريقتان رئيسيتان لنشر Java في الوقت الحاضر: استخدام إطار عمل أو استخدام حل محلي أكثر مرونة.
نظرًا لأن نشر Java ليس بالأمر السهل، فقد تم إنشاء أطر عمل يمكن أن تساعد. اثنان من الأفضل هما Dropwizard وSpring Boot. يمكن أيضًا اعتبار إطار التشغيل أحد أطر النشر هذه أيضًا.
يحاول كل منهم خفض الحاجز الذي يحول دون إخراج الكود الخاص بك من الباب. إنها مفيدة بشكل خاص إذا كنت جديدًا في استخدام Java أو إذا كنت بحاجة إلى إنجاز الأمور بسرعة. تعد عمليات نشر JAR الفردية أسهل من عمليات نشر WAR أو EAR المعقدة.
ومع ذلك، يمكن أن يكونوا غير مرنين إلى حد ما ولديهم آراء إلى حد ما، لذلك إذا كان مشروعك لا يتناسب مع الاختيارات التي قام بها مطورو إطار العمل الخاص بك، فسيتعين عليك الانتقال إلى تكوين أكثر دقة.
بديل جيد : غرادل.
لا يزال Maven هو الأداة القياسية لإنشاء اختباراتك وتعبئتها وتشغيلها. هناك بدائل، مثل Gradle، لكنها لا تتمتع بنفس التبني الذي يتمتع به Maven. إذا كنت جديدًا في Maven، فيجب أن تبدأ باستخدام Maven بالقدوة.
أحب أن يكون لدي POM جذر مع جميع التبعيات الخارجية التي تريد استخدامها. وسوف تبدو شيئا من هذا القبيل. يحتوي POM الجذري هذا على تبعية خارجية واحدة فقط، ولكن إذا كان منتجك كبيرًا بما يكفي، فسيكون لديك العشرات. يجب أن يكون POM الجذر الخاص بك مشروعًا بحد ذاته: في التحكم في الإصدار ويتم إصداره مثل أي مشروع Java آخر.
إذا كنت تعتقد أن وضع علامة على POM الجذر الخاص بك لكل تغيير في التبعية الخارجية هو أمر أكثر من اللازم، فأنت لم تضيع أسبوعًا في تتبع أخطاء التبعية عبر المشروع.
ستتضمن جميع مشاريع Maven الخاصة بك POM الجذري الخاص بك وجميع معلومات الإصدار الخاصة به. بهذه الطريقة، تحصل على الإصدار المحدد لشركتك من كل تبعية خارجية، وجميع مكونات Maven الإضافية الصحيحة. إذا كنت بحاجة إلى سحب التبعيات الخارجية، فسيعمل الأمر تمامًا كما يلي:
< dependencies >
< dependency >
< groupId >org.third.party</ groupId >
< artifactId >some-artifact</ artifactId >
</ dependency >
</ dependencies >
إذا كنت تريد تبعيات داخلية، فيجب إدارتها بواسطة كل مشروع على حدة قسم. وإلا سيكون من الصعب الحفاظ على رقم إصدار POM الجذري سليمًا.
أحد أفضل الأجزاء في Java هو الكم الهائل من مكتبات الطرف الثالث التي تقوم بكل شيء. بشكل أساسي، تحتوي كل واجهة برمجة تطبيقات أو مجموعة أدوات على Java SDK ومن السهل سحبها باستخدام Maven.
وتعتمد مكتبات Java نفسها على إصدارات محددة من المكتبات الأخرى. إذا قمت بسحب ما يكفي من المكتبات، فسوف تحصل على تعارضات في الإصدارات، أي شيء من هذا القبيل:
Foo library depends on Bar library v1.0
Widget library depends on Bar library v0.9
ما هو الإصدار الذي سيتم سحبه إلى مشروعك؟
باستخدام البرنامج المساعد لتقارب تبعيات Maven، سيحدث خطأ في البناء إذا كانت تبعياتك لا تستخدم نفس الإصدار. ثم، لديك خياران لحل الصراع:
يعتمد اختيار الخيار على موقفك: إذا كنت تريد تتبع إصدار مشروع واحد، فإن الاستبعاد أمر منطقي. من ناحية أخرى، إذا كنت تريد أن تكون واضحًا بشأن هذا الأمر، فيمكنك اختيار إصدار، على الرغم من أنك ستحتاج إلى تحديثه عند تحديث التبعيات الأخرى.
من الواضح أنك تحتاج إلى نوع من خادم التكامل المستمر الذي سيقوم بشكل مستمر ببناء إصدارات SNAPSHOT وبناء العلامات بناءً على علامات git.
يعد Jenkins و Travis-CI خيارين طبيعيين.
تعد تغطية التعليمات البرمجية مفيدة، ولدى Cobertura مكون إضافي جيد لـ Maven ودعم CI. هناك أدوات أخرى لتغطية التعليمات البرمجية لـ Java، لكنني استخدمت Cobertura.
أنت بحاجة إلى مكان لوضع ملفات JAR وWAR وEARs التي تقوم بإنشائها، لذا ستحتاج إلى مستودع.
الاختيارات الشائعة هي Artifactory وNexus. كلاهما يعملان، ولهما إيجابيات وسلبيات خاصة بهما.
يجب أن يكون لديك تثبيت Artifactory/Nexus الخاص بك وأن تعكس تبعياتك عليه. سيؤدي هذا إلى إيقاف البناء الخاص بك من الانهيار بسبب تعطل بعض مستودعات Maven الأولية.
لقد قمت الآن بتجميع التعليمات البرمجية الخاصة بك، وإعداد المستودع الخاص بك، وتحتاج إلى إخراج التعليمات البرمجية الخاصة بك في بيئة التطوير الخاصة بك ودفعها في النهاية إلى الإنتاج. لا تبخل هنا، لأن أتمتة هذا سوف تؤتي ثمارها لفترة طويلة.
تعتبر Chef وPuppet وAnsible من الخيارات النموذجية. لقد كتبت بديلاً يسمى Squadron، والذي أعتقد بالطبع أنه يجب عليك التحقق منه لأنه من الأسهل الحصول على الحق من البدائل.
بغض النظر عن الأداة التي تختارها، لا تنس أتمتة عمليات النشر الخاصة بك.
ربما تكون أفضل ميزة في Java هي الكم الهائل من المكتبات الموجودة بها. هذه مجموعة صغيرة من المكتبات التي من المحتمل أن تكون قابلة للتطبيق على أكبر مجموعة من الأشخاص.
مكتبة Java القياسية، التي كانت خطوة مذهلة إلى الأمام، تبدو الآن وكأنها تفتقد العديد من الميزات الرئيسية.
يحتوي مشروع Apache Commons على مجموعة من المكتبات المفيدة.
يحتوي برنامج Commons Codec على العديد من طرق التشفير/فك التشفير المفيدة للسلاسل Base64 والسلاسل السداسية. لا تضيع وقتك في إعادة كتابة تلك.
Commons Lang هي المكتبة المفضلة لمعالجة وإنشاء السلاسل ومجموعات الأحرف ومجموعة من الأساليب المساعدة المتنوعة.
يحتوي Commons IO على جميع الطرق المتعلقة بالملفات التي قد ترغب فيها. يحتوي على FileUtils.copyDirectory وFileUtils.writeStringToFile وIOUtils.readLines وغير ذلك الكثير.
Guava هي مكتبة Google الممتازة التي تحتوي على ما تفتقده Java. من الصعب تقريبًا استخلاص كل ما يعجبني في هذه المكتبة، لكنني سأحاول.
تعد ذاكرة التخزين المؤقت طريقة بسيطة للحصول على ذاكرة تخزين مؤقت في الذاكرة يمكن استخدامها للتخزين المؤقت للوصول إلى الشبكة أو الوصول إلى القرص أو حفظ الوظائف أو أي شيء آخر بالفعل. ما عليك سوى تنفيذ CacheBuilder الذي يخبر Guava بكيفية إنشاء ذاكرة التخزين المؤقت الخاصة بك وستكون جاهزًا!
مجموعات غير قابلة للتغيير . هناك مجموعة من هذه: ImmutableMap، أو ImmutableList، أو حتى ImmutableSortedMultiSet إذا كان هذا هو أسلوبك.
أحب أيضًا كتابة مجموعات قابلة للتغيير بطريقة الجوافة:
// Instead of
final Map < String , Widget > map = new HashMap <>();
// You can use
final Map < String , Widget > map = Maps . newHashMap ();
هناك فئات ثابتة للقوائم والخرائط والمجموعات والمزيد. إنها أنظف وأسهل في القراءة.
إذا كنت عالقًا في Java 6 أو 7، فيمكنك استخدام فئة Collections2، التي تحتوي على طرق مثل التصفية والتحويل. إنها تسمح لك بكتابة التعليمات البرمجية بطلاقة دون دعم دفق Java 8.
لدى Guava أشياء بسيطة أيضًا، مثل Joiner الذي يربط السلاسل على الفواصل وفئة للتعامل مع المقاطعات عن طريق تجاهلها.
مكتبة Google Gson هي مكتبة تحليل JSON بسيطة وسريعة. يعمل مثل هذا:
final Gson gson = new Gson ();
final String json = gson . toJson ( fooWidget );
final FooWidget newFooWidget = gson . fromJson ( json , FooWidget . class );
إنه أمر سهل حقًا ويسعدني العمل معه. يحتوي دليل مستخدم Gson على العديد من الأمثلة.
أحد مضايقاتي المستمرة مع Java هو أنها لا تحتوي على صفوف مدمجة في المكتبة القياسية. لحسن الحظ، مشروع Java tuples يصلح ذلك.
إنه سهل الاستخدام ويعمل بشكل رائع:
Pair < String , Integer > func ( String input ) {
// something...
return Pair . with ( stringResult , intResult );
}
Javaslang هي مكتبة وظيفية، مصممة لإضافة الميزات المفقودة التي كان ينبغي أن تكون جزءًا من Java 8. بعض هذه الميزات هي
هناك العديد من مكتبات Java التي تعتمد على مجموعات Java الأصلية. يقتصر ذلك على البقاء متوافقًا مع الفئات التي تم إنشاؤها بتركيز موجه للكائنات ومصممة لتكون قابلة للتغيير. مجموعات Javaslang لـ Java هي مجموعة جديدة تمامًا، مستوحاة من Haskell وClojure وScala. لقد تم إنشاؤها بتركيز وظيفي وتتبع تصميمًا ثابتًا.
رمز مثل هذا آمن تلقائيًا ولا يمكن محاولة التقاطه:
// Success/Failure containing the result/exception
public static Try < User > getUser ( int userId ) {
return Try . of (() -> DB . findUser ( userId ))
. recover ( x -> Match . of ( x )
. whenType ( RemoteException . class ). then ( e -> ...)
. whenType ( SQLException . class ). then ( e -> ...));
}
// Thread-safe, reusable collections
public static List < String > sayByeBye () {
return List . of ( "bye, " bye ", "collect" , "mania" )
. map ( String :: toUpperCase )
. intersperse ( " " );
}
Joda-Time هي أفضل مكتبة وقت استخدمتها على الإطلاق. بسيطة ومباشرة وسهلة الاختبار. ماذا يمكنك أن تطلب؟
لا تحتاج إلى هذا إلا إذا لم تكن تستخدم Java 8 بعد، حيث أن هذا الإصدار يحتوي على مكتبة وقت جديدة خاصة به وهذا ليس سيئًا.
لومبوك هي مكتبة مثيرة للاهتمام. من خلال التعليقات التوضيحية، يسمح لك بتقليل النمطية التي تعاني منها Java بشدة.
هل تريد المستوطنين والحروف لمتغيرات صفك؟ بسيط:
public class Foo {
@ Getter @ Setter private int var ;
}
الآن يمكنك القيام بذلك:
final Foo foo = new Foo ();
foo . setVar ( 5 );
وهناك الكثير. لم أستخدم لومبوك في الإنتاج بعد، لكن لا أستطيع الانتظار لذلك.
البدائل الجيدة : جيرسي أو سبارك
هناك معسكران رئيسيان للقيام بخدمات الويب RESTful في Java: JAX-RS وكل شيء آخر.
JAX-RS هي الطريقة التقليدية. يمكنك دمج التعليقات التوضيحية مع الواجهات والتطبيقات لتشكيل خدمة الويب باستخدام شيء مثل Jersey. الجميل في هذا هو أنه يمكنك بسهولة إنشاء عملاء من فئة الواجهة فقط.
يعد إطار التشغيل بمثابة طريقة مختلفة جذريًا لخدمات الويب على JVM: لديك ملف مسارات ثم تكتب الفئات المشار إليها في تلك المسارات. إنه في الواقع إطار عمل MVC كامل، ولكن يمكنك استخدامه بسهولة لخدمات ويب REST فقط.
إنه متاح لكل من Java وScala. إنها تعاني قليلاً من كونها Scala أولاً، لكنها لا تزال جيدة للاستخدام في Java.
إذا كنت معتادًا على الأطر الدقيقة مثل Flask في Python، فستكون Spark مألوفة جدًا. إنه يعمل بشكل جيد مع Java 8.
هناك الكثير من حلول تسجيل Java. المفضل لدي هو SLF4J لأنه قابل للتوصيل للغاية ويمكنه دمج السجلات من العديد من أطر التسجيل المختلفة في نفس الوقت. هل لديك مشروع غريب يستخدم java.util.logging وJCL وlog4j؟ SLF4J هو لك.
الدليل المكون من صفحتين هو كل ما تحتاجه للبدء.
أنا لا أحب أطر ORM الثقيلة لأنني أحب SQL. لذلك كتبت الكثير من قوالب JDBC وكان من الصعب صيانتها. jOOQ هو حل أفضل بكثير.
يتيح لك كتابة SQL في Java بطريقة آمنة:
// Typesafely execute the SQL statement directly with jOOQ
Result < Record3 < String , String , String >> result =
create . select ( BOOK . TITLE , AUTHOR . FIRST_NAME , AUTHOR . LAST_NAME )
. from ( BOOK )
. join ( AUTHOR )
. on ( BOOK . AUTHOR_ID . equal ( AUTHOR . ID ))
. where ( BOOK . PUBLISHED_IN . equal ( 1948 ))
. fetch ();
باستخدام هذا ونمط DAO، يمكنك جعل الوصول إلى قاعدة البيانات أمرًا سهلاً.
يعد الاختبار أمرًا بالغ الأهمية لبرنامجك. هذه الحزم تساعد على تسهيل الأمر.
بديل جيد : TestNG.
jUnit لا يحتاج إلى مقدمة. إنها الأداة القياسية لاختبار الوحدة في Java.
لكن ربما لا تستخدم jUnit بكامل إمكاناته. تدعم jUnit الاختبارات ذات المعلمات، والقواعد التي تمنعك من كتابة الكثير من القواعد المعيارية، والنظريات لاختبار تعليمات برمجية معينة بشكل عشوائي، والافتراضات.
إذا كنت قد قمت بحقن التبعية، فهذا هو المكان الذي يؤتي ثماره: الاستهزاء بالكود الذي له آثار جانبية (مثل التحدث إلى خادم REST) والاستمرار في تأكيد سلوك الكود الذي يستدعيه.
jMock هي أداة السخرية القياسية لجافا. يبدو مثل هذا:
public class FooWidgetTest {
private Mockery context = new Mockery ();
@ Test
public void basicTest () {
final FooWidgetDependency dep = context . mock ( FooWidgetDependency . class );
context . checking ( new Expectations () {{
oneOf ( dep ). call ( with ( any ( String . class )));
atLeast ( 0 ). of ( dep ). optionalCall ();
}});
final FooWidget foo = new FooWidget ( dep );
Assert . assertTrue ( foo . doThing ());
context . assertIsSatisfied ();
}
}
يؤدي ذلك إلى إعداد FooWidgetDependency عبر jMock ثم إضافة التوقعات. نتوقع أن يتم استدعاء أسلوب الاستدعاء dep مرة واحدة باستخدام سلسلة ما، وأن يتم استدعاء أسلوب الاتصال الاختياري dep هذا صفر مرة أو أكثر.
إذا كان عليك إعداد نفس التبعية مرارًا وتكرارًا، فمن المحتمل أن تضع ذلك في أداة اختبار وأن تضع AssurIsSatisfied في أداة @After .
هل سبق لك أن فعلت هذا مع jUnit؟
final List < String > result = some . testMethod ();
assertEquals ( 4 , result . size ());
assertTrue ( result . contains ( "some result" ));
assertTrue ( result . contains ( "some other result" ));
assertFalse ( result . contains ( "shouldn't be here" ));
هذا مجرد قالب مزعج. AssertJ يحل هذا. يمكنك تحويل نفس الكود إلى هذا:
assertThat ( some . testMethod ()). hasSize ( 4 )
. contains ( "some result" , "some other result" )
. doesNotContain ( "shouldn't be here" );
هذه الواجهة بطلاقة تجعل اختباراتك أكثر قابلية للقراءة. أكثر ما يمكن أن تريد؟
البدائل الجيدة : Eclipse وNetbeans
أفضل Java IDE هو IntelliJ IDEA. إنه يحتوي على الكثير من الميزات الرائعة، وهو حقًا الشيء الرئيسي الذي يجعل لغة Java قابلة للتنفيذ. يعد الإكمال التلقائي أمرًا رائعًا، وعمليات الفحص من الدرجة الأولى، وأدوات إعادة البناء مفيدة حقًا.
يعد إصدار المجتمع المجاني جيدًا بما فيه الكفاية بالنسبة لي، ولكن هناك الكثير من الميزات الرائعة في الإصدار Ultimate مثل أدوات قاعدة البيانات ودعم Spring Framework وChronon.
كانت إحدى الميزات المفضلة لدي في GDB 7 هي القدرة على العودة بالزمن إلى الوراء عند تصحيح الأخطاء. هذا ممكن مع البرنامج المساعد Chronon IntelliJ عندما تحصل على الإصدار النهائي.
يمكنك الحصول على سجل متغير وخطوة إلى الوراء وسجل الطريقة والمزيد. من الغريب بعض الشيء استخدامه في المرة الأولى، لكنه يمكن أن يساعد في تصحيح بعض الأخطاء المعقدة، مثل Heisenbugs وما شابه.
بديل جيد : DCEVM
غالبًا ما يكون التكامل المستمر هدفًا لمنتجات البرامج كخدمة. ماذا لو لم تكن بحاجة حتى إلى الانتظار حتى انتهاء الإنشاء لرؤية تغييرات التعليمات البرمجية مباشرة؟
هذا ما يفعله JRebel. بمجرد ربط الخادم الخاص بك بعميل JRebel الخاص بك، يمكنك رؤية التغييرات على الخادم الخاص بك على الفور. إنه توفير كبير للوقت عندما تريد التجربة بسرعة.
نظام الكتابة في Java ضعيف جدًا. إنه لا يفرق بين السلاسل والسلاسل التي هي في الواقع تعبيرات عادية، ولا يقوم بأي فحص للعيوب. ومع ذلك، فإن إطار عمل المدقق يفعل هذا وأكثر.
يستخدم التعليقات التوضيحية مثل @Nullable للتحقق من الأنواع. يمكنك أيضًا تحديد التعليقات التوضيحية الخاصة بك لجعل التحليل الثابت أكثر قوة.
حتى عند اتباع أفضل الممارسات، فحتى أفضل المطورين سوف يرتكبون الأخطاء. هناك عدد من الأدوات التي يمكنك استخدامها للتحقق من صحة كود Java الخاص بك لاكتشاف المشكلات في الكود الخاص بك. يوجد أدناه مجموعة صغيرة من بعض الأدوات الأكثر شيوعًا. يتكامل الكثير منها مع بيئة التطوير المتكاملة (IDE) الشائعة مثل Eclipse أو IntelliJ مما يتيح لك اكتشاف الأخطاء في التعليمات البرمجية الخاصة بك في وقت أقرب.
بالإضافة إلى استخدام هذه الأدوات أثناء التطوير، غالبًا ما يكون من الجيد تشغيلها أيضًا أثناء مراحل الإنشاء. يمكن ربطها بأدوات البناء مثل Maven أو Gradle وأيضًا بأدوات التكامل المستمر.
يحدث تسرب للذاكرة، حتى في Java. ولحسن الحظ، هناك أدوات لذلك. أفضل أداة استخدمتها لإصلاح هذه المشكلة هي Eclipse Memory Analyzer. يستغرق تفريغ الكومة ويتيح لك العثور على المشكلة.
هناك عدة طرق للحصول على تفريغ الكومة لعملية JVM، لكني أستخدم jmap:
$ jmap -dump:live,format=b,file=heapdump.hprof -F 8152
Attaching to process ID 8152, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 23.25-b01
Dumping heap to heapdump.hprof ...
... snip ...
Heap dump file created
وبعد ذلك يمكنك فتح ملف heapdump.hprof باستخدام Memory Analyzer ومعرفة ما يحدث بسرعة.
موارد لمساعدتك على أن تصبح محترفًا في Java.