يتم عرض ما يلي للجميع على كل سوء فهم.
1. استخدام NULL المفرط
تجنب الاستخدام المفرط للخلفي هو أفضل الممارسات. على سبيل المثال ، يتمثل طريقة أفضل في جعل الطريقة تعود إلى الصفيف أو المجموعة الفارغة بدلاً من القيمة الخالية ، لأن هذا يمكن أن يمنع البرنامج من رمي NullPointerxception. سيحصل جزء الرمز التالي على مجموعة من طريقة أخرى:
قائمة <Tring> accountids = person.getAccountids () ؛
عندما لا يكون لدى الرقم حساب ، فإن GetAccountids () سيعيد القيمة الخالية ، وسيقوم البرنامج بإلقاء استثناء NullPointerException. لذلك ، من الضروري الانضمام إلى فحص الهواء لحل هذه المشكلة. إذا استبدلت القيمة الفارغة التي تم إرجاعها بقائمة فارغة ، فلن يظهر NullPointerException. علاوة على ذلك ، نظرًا لأننا لم نعد بحاجة إلى إجراء فحص قصير لـ accountid المتغير ، فإن الرمز سيصبح أكثر إيجازًا.
عندما تريد تجنب القيم الخالية ، قد تأخذ سيناريوهات مختلفة ممارسات مختلفة. تتمثل إحدى الطرق في استخدام النوع الاختياري ، والذي يمكن أن يكون كائنًا فارغًا أو حزمة من بعض القيم.
اختياري <String> OptionalString = expression.ofnullable (NulledString) ؛
في الواقع ، يوفر Java8 طريقة أكثر إيجازًا:
اختياري <String> OptectalString = اختياري.
دعمت Java النوع الاختياري من إصدار Java8 ، ولكن كان معروفًا على نطاق واسع في عالم البرمجة الوظيفية. قبل ذلك ، تم استخدامه في الإصدار المبكر من Java في Google Guava.
2. تجاهل التشوهات
غالبا ما نتجاهل التشوهات. ومع ذلك ، فإن أفضل الممارسات هي التعامل معهم للمبتدئين ومبرمجي Java ذوي الخبرة. عادة ما يكون الرمي غير الطبيعي هادفًا ، لذلك في معظم الحالات ، من الضروري تسجيل الأحداث التي تسبب تشوهات. لا تقلل من شأن هذه المسألة. على الأقل ، من أجل السماح للمطورين الآخرين بمعرفة السبب والتأثير ، يجب أن تشرح سبب عدم التعامل مع هذه التشوهات.
selfie = person.shootselfie () ؛
هناك طريقة بسيطة للتأكيد على بعض الأهم من ذلك وهي استخدام هذه المعلومات كاسم متغير غير طبيعي ، مثل هذا:
نسخ رمز رمز على النحو التالي:
حاول {selfie.delete () ؛} catch (nullPointException غير مهم) {}
3. تعديل التشوهات بشكل متزامن
يحدث هذا الشذوذ في كائن المجموعة ، وفي الوقت نفسه لا يستخدم الطريقة التي يوفرها كائن ITerator لتحديث المحتوى في المجموعة. على سبيل المثال ، هناك قائمة قبعات هنا ، وتريد حذف جميع القيم التي تحتوي على اللوحات الأذن:
قائمة <hats = new ArtyList <>) ؛ hasearflaps ()) {hats.remove (hat) ؛}}
إذا تم تشغيل هذا الرمز ، فسيتم إلقاء ConcurrentModificationException ، لأن الرمز سيعدله أثناء عبور هذه المجموعة. عندما تعمل عمليات متعددة على نفس القائمة ، عندما تعبر إحدى العمليات القائمة ، تحاول العملية الأخرى تعديل محتوى القائمة ، وقد تحدث نفس التشوهات أيضًا.
إنه أمر شائع جدًا في محتوى جمع التعديل المتزامن متعدد الخيوط ، لذلك من الضروري استخدام الطريقة المستخدمة عادة في البرمجة المتزامنة ، مثل الأقفال المتزامنة ، ومجموعات خاصة للتعديل المتزامن ، وما إلى ذلك. Java يحل هذه المشكلة في خيط واحد وموقف متعدد الفقرة.
جمع الأشياء وحذفها في دورة أخرى
الحل المباشر هو وضع القبعات مع اللوحات الأذن في قائمة ، ثم حذفها بدورة أخرى. ومع ذلك ، فإن هذا يتطلب مجموعة إضافية لتخزين القبعات التي يجب حذفها.
القائمة <ihatstoremove = new LinkedList <> () ؛
استخدم طريقة iterator.remove
هذه الطريقة أبسط ، وفي الوقت نفسه لا تحتاج إلى إنشاء مجموعة إضافية:
iterator <ihatitrator = hats.iterator () ؛
طريقة استخدام ListIterator
عند تطبيق مجموعة واجهة القائمة ، يعد ITerator القائمة اختيارًا مناسبًا للغاية. لا تدعم Iterator التي تنفذ واجهة Listitoror عمليات الحذف فحسب ، بل تدعم أيضًا عمليات إضافة وتعيين العمليات. تقوم واجهة Listotrator بتنفيذ واجهة Iterator ، لذلك يبدو هذا المثال مشابهًا لطريقة إزالة ITerator. الفرق الوحيد هو نوع التكرار قبعة ونحصل على طريقة التكرار -باستخدام طريقة ListTrator (). تُظهر الشظايا التالية كيفية استخدام طريقة LITTERTERATOR.REMOVE و LISTOTRATOR.ADD لاستبدال قبعة الأذن مع SOM <OMBREROS.
ihat sombrero = new Sombrero () ؛ ؛
باستخدام ListIratorator ، يمكن استبدال طريقة الاتصال وإضافة طريقة للاتصال بأسلوب مجموعة واحدة فقط:
ihat sombrero = new Sombrero () ؛ ) ؛
استخدم طريقة الدفق في Java 8
في Java8 ، يمكن للمطورين تحويل مجموعة إلى تيار وتصفية دفق وفقًا لبعض الشروط. يخبر هذا المثال كيف تتساقط قبعات مرشح API لتدفق وتجنب ConvalrentModificationException. القبعات = hats.stream ().
نسخ رمز رمز على النحو التالي:
.Collect (collectors.tocollection (ArrayList :: New)) ؛
ستنشئ طريقة collectors.tocollection قائمة ArrayList جديدة ، وهي مسؤولة عن تخزين قيمة القبعات المصفاة. إذا تم ترشيح شروط التصفية خارج عدد كبير من الإدخالات ، فسيتم إنشاء قائمة Arraylist كبيرة هنا. لذلك ، تحتاج إلى استخدامه بحذر.
استخدم طريقة list.removeif في Java 8
يمكنك استخدام طريقة أخرى أكثر إيجازًا وواضحًا في طريقة Java 8 -removeif:
نسخ رمز رمز على النحو التالي:
hats.removeif (ihat :: hasearflaps) ؛
في الأسفل ، يستخدم iterator.remove لإكمال هذه العملية.
استخدم مجموعة خاصة
إذا قررت استخدام CopyOnWriteArrayList بدلاً من ArrayList في البداية ، فلن تكون هناك مشكلة. نظرًا لأن CopyOnWriteArrayList يوفر طرقًا معدلة (مثل المجموعة ، إضافة ، إزالة) ، فلن يغير مجموعة المجموعة الأصلية ، ولكنها تنشئ نسخة معدلة جديدة. يتيح هذا اجتياز تعديل الإصدار الأصلي ، بحيث لا يتم التخلص من ConcurrentModificationException. عيوب هذه المجموعة واضحة للغاية -يتم إنشاء مجموعة جديدة لكل تعديل.
هناك مجموعات أخرى مناسبة لسيناريوهات مختلفة ، مثل CopyOnwriteset و ConcurrenthashMap.
فيما يتعلق بالخطأ الآخر الذي قد يحدث أثناء التعديلات المتزامنة ، فإنه ينشئ دفقًا من مجموعة. يتمثل المعيار العام للبث في تجنب تعديل المجموعة الخلفية عند التحقق من الدفق. يوضح المثال التالي كيفية التعامل بشكل صحيح مع الدفق:
قائمة <Hat> filedhats = hats.stream ().
تقوم طريقة PEEK بجمع جميع العناصر وتنفذ إجراءات ثابتة لكل عنصر. هنا ، الإجراء هو محاولة حذف البيانات من قائمة أساسية ، والتي من الواضح أنها خاطئة. لتجنب مثل هذه العمليات ، يمكنك تجربة بعض الطرق الموضحة أعلاه.
4. الدفاع
في بعض الأحيان ، من أجل التعاون بشكل أفضل ، يجب أن يمتثل الرمز الذي توفره المكتبة القياسية أو الطرف الثالث للتبعيات الشائعة. على سبيل المثال ، من الضروري الامتثال للاتفاق المشترك بين Hashcode ومساواة لضمان أن سلسلة من فئات التجميع في إطار مجموعة Java والفئات الأخرى التي تستخدم الأساليب HashCode والمساواة يمكن أن تعمل بشكل طبيعي. لا تتوافق مع أخطاء مثل استثناء أو تجميع الكود ؛
قد يتسلل رمز الخطأ إلى بيئة الإنتاج ، مما يسبب الكثير من الآثار الضارة. ويشمل ذلك ضعف خبرة واجهة المستخدم ، وتقارير البيانات الخاطئة ، وأداء التطبيق الضعيف ، وفقدان البيانات أو أكثر. لحسن الحظ ، لا تحدث هذه الأخطاء الكارثية في كثير من الأحيان. تم ذكر علامة التجزئة والمتساوية من قبل أن المشهد قد يبدو: المجموعة تعتمد على الهدف لمقارنة الكائنات أو المقارنات ، تمامًا مثل HashMap و Hashset. بعبارات بسيطة ، هناك معاييران لهذه الاتفاقية:
إذا كان الكائنان متساويان ، فيجب أن يكون رمز التجزئة متساويًا.
إذا كان للكائنين نفس رمز التجزئة ، فقد يكونان متساويان أو مختلفان.
المعيار الأول للتدمير ، عندما تحاول استرداد البيانات من hashmap ، فإنه سيؤدي إلى أخطاء. المعيار الثاني يعني أن الكائنات ذات نفس رمز التجزئة ليست متساوية بالضرورة.
دعونا نلقي نظرة على عواقب تدمير المعيار الأول:
قارب فئة ثابتة {اسم سلسلة خاصة (اسم سلسلة) {this.name = name ؛ getClass ()! int hashcode () {return (int) (Math.Random () * 5000) ؛}}
كما ترون ، يعيد فئة القوارب كتابة أساليب المساواة والرمز. ومع ذلك ، فقد دمر الاتفاق لأن Hashcode أعاد القيمة العشوائية لنفس الكائن لكل مكالمة. من المحتمل ألا يجد الرمز التالي قاربًا يسمى Enterprise في Hashset ، على الرغم من أننا في الواقع أضفنا هذا النوع من القوارب مقدمًا:
الفراغ الثابت العام (String [] args) {set <Boat> boats = new hashset <> () ؛ (قارب جديد ("Enterprise")) ؛} ؛}
اتفاق آخر هو طريقة الانتهاء. فيما يلي إشارة إلى وثيقة Java الرسمية حول وصفها الوظيفي:
الاتفاق التقليدي لـ Finize هو: عندما يحدد الجهاز الظاهري Javatm أن أي مؤشر ترابط لم يعد قادرًا على الوصول إلى الكائن المحدد بأي شكل من الأشكال ، سيتم استدعاء هذه الطريقة. تحتوي طريقة النهائيات على وظائف متعددة ، بما في ذلك استخدام هذا الكائن ليكون متاحًا للمواضيع الأخرى مرة أخرى ، ومع ذلك ، فإن الغرض الرئيسي من الانتهاء هو إجراء عمليات واضحة قبل التخلص من الكائنات التي لا رجعة فيها. على سبيل المثال ، يمكن لطريقة اللمسات الأخيرة التي تشير إلى كائن اتصال الإدخال/الإخراج تنفيذ معاملة الإدخال/الإخراج الصريحة لمقاطعة الاتصال قبل الكائن الدائم المهمل.
يمكنك أن تقرر استخدام طريقة الانتهاء في معالج الملفات لإصدار الموارد ، ولكن هذا الاستخدام سيء. نظرًا لأنه يسمى أثناء إعادة تدوير القمامة ووقت GC غير متأكد ، فلن يتم ضمان وقت الانتهاء.
5. استخدم النوع الأصلي بدلاً من المعلمة
وفقًا لوصف وثيقة Java: فإن النوع الأصلي إما غير مميت ، أو عضوًا غير منتظم في RM (أيضًا غير مُلسِّم من الوالدين أو الوالد الوالد). قبل تقديم النوع العام Java ، لم يكن هناك نوع بديل بدائي. دعمت Java البرمجة العامة من الإصدار 1.5 ، وليس هناك شك في أن هذا تحسين مهم للوظيفة. ومع ذلك ، بسبب التوافق المتخلف ، هناك فخ قد يدمر نظام النوع بأكمله. جاهدة مثال:
listofnumbers = new ArtyList () ؛
هذه قائمة بالأرقام التي يتم تعريفها على أنها قائمة ArrayList الأصلية. نظرًا لأنه لا يحدد معلمات النوع ، يمكنه إضافة أي كائن إليه. ومع ذلك ، فإن السطر الأخير يقوم بتعيين العناصر التي يحتوي عليها من نوع int وضربها بمقدار 2 ، طبع البيانات بعد مضاعفة البيانات إلى الإخراج القياسي.
لن يرتكب هذا الرمز خطأً أثناء التجميع ، ولكن بمجرد تشغيله ، فإنه سوف يرمي خطأ عند تشغيله ، لأنه يحاول تعيين نوع الحرف إلى الجراحة التجميلية. من الواضح ، إذا تم إخفاء المعلومات اللازمة ، فلن يساعد نظام النوع في كتابة رمز الأمان.
لحل هذه المشكلة ، تحتاج إلى تحديد النوع المحدد للكائنات في المجموعة:
قائمة <Nereger> listofnumbers = new ArtyList <() () ؛
الفرق الوحيد من الكود السابق هو السطر الذي يحدد المجموعة:
نسخ رمز رمز على النحو التالي:
قائمة <integer> listOfNumbers = new ArrayList <() ؛
لا يمكن تمرير تجميع الكود المعدل لأنه يحاول إضافة سلسلة إلى مجموعة من البلاستيك التخزين المتوقع فقط. سيعرض المترجم رسالة خطأ ويشير إلى السطر الذي يضيف عشرين حرفًا إلى القائمة. المعلمة النوع العام فكرة جيدة. في هذه الحالة ، يمكن للمترجم التحقق من الأنواع المحتملة ، بحيث يتم تقليل الفرصة غير الطبيعية لوقت التشغيل بسبب التناقضات إلى حد كبير.
غالبًا ما يرتكب الملخص الرئيسي لمبرمجي Java الخمسة أعلاه أخطاء ، وآمل أن يتمكن الجميع من إعجابهم بذلك.