سؤال

إذا حصلت على NullPointerException في مكالمة مثل هذا:

someObject.getSomething().getSomethingElse().
    getAnotherThing().getYetAnotherObject().getValue();

أحصل على نص استثناء عديم الفائدة إلى حد ما مثل:

Exception in thread "main" java.lang.NullPointerException
at package.SomeClass.someMethod(SomeClass.java:12)

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

Foo ret1 = someObject.getSomething();
Bar ret2 = ret1.getSomethingElse();
Baz ret3 = ret2.getAnotherThing();
Bam ret4 = ret3.getYetAnotherOject();
int ret5 = ret4.getValue();

ثم انتظر NullPointerException أكثر وصفًا والذي يخبرني بالخط الذي يجب البحث عنه.

قد يجادل البعض منكم بأن تسلسل الحروف هو أسلوب سيء ويجب تجنبه على أي حال، ولكن سؤالي هو:هل يمكنني العثور على الخطأ دون تغيير الكود؟

تَلمِيح:أنا أستخدم Eclipse وأعرف ما هو مصحح الأخطاء، لكن لا يمكنني معرفة كيفية تطبيقه على المشكلة.

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

لقد قبلت الإجابة التي علمتني بالضبط متى أقوم بتسلسل الحروف:

  • إذا لم يتمكنوا من العودة فارغة، قم بتقييدهم طالما أردت.لا داعي للتحقق != null، ولا داعي للقلق بشأن NullPointerExceptions (كن حذرًا من أن التقييد لا يزال يخالف قانون ديميتر، لكن يمكنني التعايش مع ذلك)
  • إذا كان من الممكن أن يُرجعوا قيمة فارغة، فلا تقم أبدًا بربطها أبدًا، وقم بإجراء فحص للقيم الخالية في كل واحدة قد تُرجع قيمة فارغة

وهذا يجعل أي نصيحة جيدة بشأن التصحيح الفعلي عديمة الفائدة.

هل كانت مفيدة؟

المحلول

تعتمد الإجابة على كيفية عرضك (لعقد) الحاصلين عليك.إذا كان من الممكن أن يعودوا null يجب عليك التحقق من قيمة الإرجاع في كل مرة.إذا كان يجب ألا يعود المُستقبل null, ، يجب أن يحتوي المُحضر على شيك ويطرح استثناءً (IllegalStateException؟) بدلا من العودة null, ، التي وعدتني بعدم العودة أبدًا.سوف يوجهك تتبع المكدس إلى المُحصل الدقيق.يمكنك أيضًا وضع الحالة غير المتوقعة التي عثر عليها المُرسل في رسالة الاستثناء.

نصائح أخرى

NPE هو الاستثناء الأكثر عديمة الفائدة في Java، هذه الفترة.يبدو أنه يتم تنفيذه دائمًا بتكاسل ولا يخبرنا أبدًا عن سبب حدوثه، حتى لو كان الأمر بسيطًا مثل "الفئة x.y.Z خالية" من شأنها أن تساعد كثيرًا في تصحيح مثل هذه الحالات.

على أي حال، الطريقة الجيدة الوحيدة التي وجدتها للعثور على قاذف NPE في هذه الحالات هي النوع التالي من إعادة البناء:

someObject.getSomething()
          .getSomethingElse()
          .getAnotherThing()
          .getYetAnotherObject()
          .getValue();

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

في IntelliJ IDEA يمكنك ضبط Exceptionbreakpoints.يتم تنشيط نقاط التوقف هذه عندما يتم طرح استثناء محدد (يمكنك توسيع نطاق ذلك إلى حزمة أو فئة).

بهذه الطريقة سيكون من السهل العثور على مصدر NPE الخاص بك.

أفترض أنه يمكنك القيام بشيء مماثل في netbeans أو Eclipse.

يحرر: هنا هو شرح لكيفية إضافة نقطة توقف الاستثناء في Eclipse

إذا وجدت نفسك تكتب كثيرًا:

a.getB().getC().getD().getE();

من المحتمل أن تكون هذه رائحة رمزية ويجب تجنبها.يمكنك إعادة البناء، على سبيل المثال، في a.getE() الذي يدعو b.getE() الذي يدعو c.getE() الذي يدعو d.getE().(قد لا يكون هذا المثال منطقيًا بالنسبة لحالة الاستخدام الخاصة بك، ولكنه أحد الأنماط لإصلاح رائحة الكود هذه.)

أنظر أيضاً قانون ديميتر, ، الذي يقول:

  • يمكن لطريقتك استدعاء طرق أخرى في فئتها مباشرة
  • يمكن لطريقتك استدعاء الأساليب في الحقول الخاصة بها مباشرة (ولكن ليس في حقول الحقول)
  • عندما تأخذ طريقتك معلمات، يمكن لطريقتك استدعاء الأساليب الموجودة على تلك المعلمات مباشرة.
  • عندما تقوم طريقتك بإنشاء كائنات محلية، يمكن لهذه الطريقة استدعاء الأساليب على الكائنات المحلية.

ولذلك، لا ينبغي للمرء أن يكون لديه سلسلة من الرسائل، على سبيل المثال. a.getB().getC().doSomething().إن اتباع هذا "القانون" له العديد من الفوائد بصرف النظر عن تسهيل تصحيح أخطاء NullPointerExceptions.

أنا عمومًا لا أقوم بتسلسل الحروف مثل هذا حيث يوجد أكثر من حرف لاغٍ.

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

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

وفي الوقت نفسه يمكننا أن نحلم مشغل الملاحة الآمن في رائع

الفشل المبكر هو أيضًا خيار.

في أي مكان في التعليمات البرمجية الخاصة بك يمكن إرجاع قيمة فارغة، فكر في تقديم فحص لقيمة إرجاع فارغة.

public Foo getSomething()
{
  Foo result;
  ...
  if (result == null) {
    throw new IllegalStateException("Something is missing");
  }
  return result;
}

إليك كيفية العثور على الخطأ باستخدام Eclipse.

أولاً، قم بتعيين نقطة توقف على السطر:

someObject.getSomething().getSomethingElse().
getAnotherThing().getYetAnotherObject().getValue();

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

الآن، قم بتمييز "someObject" ثم اضغط على CTRL+SHIFT+I (أو انقر بزر الماوس الأيمن وقل "فحص").

هل هي فارغة؟لقد وجدت NPE الخاص بك.هل هي غير فارغة؟ثم قم بتمييز someObject.getSomething() (بما في ذلك الأقواس) وافحصه.هل هي فارغة؟إلخ.تابع أسفل السلسلة لمعرفة مكان حدوث NPE الخاص بك، دون الحاجة إلى تغيير التعليمات البرمجية الخاصة بك.

قد ترغب في الرجوع إلى هذا السؤال حول تجنب != null.

في الأساس، إذا كانت null استجابة صالحة، فيجب عليك التحقق منها.إذا لم يكن الأمر كذلك، أكد ذلك (إذا استطعت).ولكن مهما فعلت، حاول تقليل الحالات التي يكون فيها null استجابة صالحة لهذا من بين أسباب أخرى.

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

إذا كان لديك طريقة أو مُنشئ يأخذ معلمة كائن ولا يمكن للكائن/الطريقة المعنية التعامل بشكل معقول مع كون هذه المعلمة فارغة، فما عليك سوى التحقق من NullPointerException وإلقاءه هناك وبعد ذلك.

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

تمثل التعبيرات المتسلسلة مثل تلك صعوبة في تصحيح أخطاء NullPointerExceptions (ومعظم المشكلات الأخرى التي يمكن أن تحدث) لذا أنصحك بمحاولة تجنبها.ربما تكون قد سمعت ذلك بما فيه الكفاية، وكما ذكرنا في الملصق السابق، يمكنك إضافة نقاط فاصل على NullPointerException الفعلي لمعرفة مكان حدوثه.

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

إذا كنت تتحكم في الطريقة التي تُرجع القيمة null، فيمكنك أيضًا التفكير في نمط Null Object إذا كانت القيمة null صالحة للإرجاع.

ضع كل مُحصل على السطر الخاص به وقم بتصحيح الأخطاء.انتقل إلى (F6) كل طريقة للعثور على المكالمة التي ترجع فارغة

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top