سؤال

لدي طريقة ضبط بسيطة للممتلكات و null غير مناسب لهذه الخاصية بالذات.لقد كنت دائمًا ممزقًا في هذا الموقف:هل يجب أن أرمي IllegalArgumentException, ، أو أ NullPointerException؟من javadocs، يبدو كلاهما مناسبًا.هل هناك نوع من المعيار المفهوم؟أم أن هذا مجرد أحد تلك الأشياء التي يجب عليك القيام بها كما تفضل وكلاهما صحيح حقًا؟

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

المحلول

يبدو وكأنه IllegalArgumentException يتم استدعاؤك إذا كنت لا تريد null أن تكون قيمة مسموح بها، و NullPointerException سيتم طرحها إذا كنت تحاول ذلك يستخدم المتغير الذي تبين أن يكون null.

نصائح أخرى

يجب أن تستخدم IllegalArgumentException (IAE)، لا NullPointerException (NPE) للأسباب التالية:

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

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

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

رابعًا، جميع بيانات المعلمات الأخرى غير الصحيحة ستكون IAE، فلماذا لا تكون متسقة؟لماذا هو أن غير قانوني null خاص جدًا لدرجة أنه يستحق استثناءً منفصلاً عن جميع أنواع الحجج غير القانونية الأخرى؟

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

المعيار هو رمي NullPointerException.تناقش "Java الفعالة" المعصومة بشكل عام هذا الأمر باختصار في البند 42 (الإصدار الأول)، أو البند 60 (الإصدار الثاني)، أو البند 72 (الإصدار الثالث) "تفضيل استخدام الاستثناءات القياسية":

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

كنت كل شيء لصالح الرمي IllegalArgumentException للمعلمات الفارغة، حتى اليوم، عندما لاحظت java.util.Objects.requireNonNull الطريقة في جافا 7بهذه الطريقة، بدلًا من القيام بما يلي:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

يمكنك ان تفعل:

Objects.requireNonNull(param);

وسوف يرمي NullPointerException إذا كانت المعلمة التي تمررها هي null.

بالنظر إلى أن هذه الطريقة صحيحة في المنتصف java.util أنا أعتبر وجوده مؤشرًا قويًا جدًا على أن الرمي NullPointerException هي "طريقة جافا لفعل الأشياء".

أعتقد أنني قررت على أي حال.

لاحظ أن الحجج المتعلقة بالتصحيح الصعب زائفة لأنه يمكنك بالطبع إرسال رسالة إليها NullPointerException قول ما كان باطلاً ولماذا لا ينبغي أن يكون باطلاً.تماما مثل مع IllegalArgumentException.

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

أميل إلى متابعة تصميم مكتبات JDK، وخاصة المجموعات والتزامن (Joshua Bloch، Doug Lea، هؤلاء الأشخاص يعرفون كيفية تصميم واجهات برمجة التطبيقات الصلبة).على أي حال، العديد من واجهات برمجة التطبيقات في JDK يتم طرحها بشكل استباقي NullPointerException.

على سبيل المثال، Javadoc ل Map.containsKey تنص على:

throws nullpointerxception إذا كان المفتاح فارغًا ولا تسمح هذه الخريطة بمفاتيح فارغة (اختيارية).

من الصحيح تمامًا رمي NPE الخاص بك.تتمثل الاتفاقية في تضمين اسم المعلمة الذي كان فارغًا في رسالة الاستثناء.

النمط يذهب:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

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

صوتوا لصالح حجة جيسون كوهين لأنها قدمت بشكل جيد.اسمحوا لي أن أقطعها خطوة بخطوة.؛-)

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

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

  • سأختار نبي زيادة IAE لأسباب متعددة

    • إنها أكثر تحديدًا حول طبيعة العملية غير القانونية
    • المنطق الذي يسمح عن طريق الخطأ بالقيم الخالية يميل إلى أن يكون مختلفًا تمامًا عن المنطق الذي يسمح عن طريق الخطأ بقيم غير قانونية.على سبيل المثال، إذا كنت أقوم بالتحقق من صحة البيانات التي أدخلها المستخدم، وإذا حصلت على قيمة غير مقبولة، فإن مصدر هذا الخطأ هو المستخدم النهائي للتطبيق.إذا حصلت على قيمة فارغة، فهذا خطأ مبرمج.
    • يمكن أن تتسبب القيم غير الصالحة في حدوث أشياء مثل تجاوز سعة المكدس، وأخطاء نفاد الذاكرة، واستثناءات التحليل، وما إلى ذلك.في الواقع، تظهر معظم الأخطاء بشكل عام، في مرحلة ما، كقيمة غير صالحة في بعض استدعاءات الأساليب.لهذا السبب أرى أن IAE هو في الواقع الأكثر عمومية لجميع الاستثناءات ضمن RuntimeException.
  • في الواقع، يمكن أن تؤدي الوسائط غير الصالحة الأخرى إلى جميع أنواع الاستثناءات الأخرى. UnknownHostException, FileNotFoundException, ، مجموعة متنوعة من استثناءات الأخطاء في بناء الجملة، IndexOutOfBoundsException, ، فشل المصادقة، الخ، الخ.

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

إنه سؤال على طراز "الحرب المقدسة".وبعبارة أخرى، كلا البديلين جيدان، ولكن سيكون لدى الناس تفضيلاتهم التي سيدافعون عنها حتى الموت.

إذا كان أ setter طريقة و null يتم تمريره إليه، وأعتقد أنه سيكون من المنطقي أكثر لرمي IllegalArgumentExceptionNullPointerException يبدو أنه أكثر منطقية في الحالة التي تحاول فيها استخدام null.

لذا، إذا كنت تستخدمه وهو كذلك null, NullPointer.إذا تم تمريره وهو كذلك null, IllegalArgument.

أباتشي كومنز لانج لديه NullArgumentException هذا يفعل عددًا من الأشياء التي تمت مناقشتها هنا:يقوم بتوسيع IllegalArgumentException ويأخذ منشئه الوحيد اسم الوسيطة التي يجب أن تكون غير فارغة.

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

لا يمكن أن أتفق أكثر مع ما يقال.تفشل مبكرا، تفشل بسرعة.تعويذة استثناء جيدة جدا.

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

بلدي 2 سنتا

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

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

ليس لديك أي سبب فعليًا لاستخدام "NullPointerException" ضمنيًا.يعد NullPointerException استثناءً تم طرحه بواسطة Java Virtual Machine عند محاولة تنفيذ تعليمات برمجية على مرجع فارغ (مثل إلى سلسلة()).

في الواقع، مسألة طرح IllegalArgumentException أو NullPointerException هي من وجهة نظري المتواضعة مجرد "حرب مقدسة" لأقلية لديها فهم غير كامل للتعامل مع الاستثناءات في Java.بشكل عام، القواعد بسيطة، وهي كما يلي:

  • يجب الإشارة إلى انتهاكات قيود الوسيطة في أسرع وقت ممكن (-> فشل سريع)، وذلك لتجنب الحالات غير القانونية التي يصعب تصحيحها
  • في حالة وجود مؤشر فارغ غير صالح لأي سبب من الأسباب، قم بطرح NullPointerException
  • في حالة وجود فهرس صفيف/مجموعة غير قانوني، قم برمي ArrayIndexOutOfBounds
  • في حالة وجود حجم صفيف/مجموعة سلبي، قم بطرح NegativeArraySizeException
  • في حالة وجود وسيطة غير قانونية لا يغطيها ما ورد أعلاه، والتي ليس لديك نوع استثناء آخر أكثر تحديدًا لها، قم بطرح IllegalArgumentException كسلة مهملات
  • من ناحية أخرى، في حالة حدوث انتهاك للقيد داخل حقل لا يمكن تجنبه عن طريق الفشل السريع لسبب وجيه، يمكنك التقاطه وإعادة طرحه باعتباره IllegalStateException أو استثناء محدد أكثر تحديدًا.لا تسمح مطلقًا بتمرير NullPointerException وArrayIndexOutOfBounds وما إلى ذلك في هذه الحالة!

هناك على الأقل ثلاثة أسباب وجيهة للغاية ضد حالة تعيين جميع أنواع انتهاكات قيود الوسيطة إلى IllegalArgumentException، ومن المحتمل أن يكون السبب الثالث شديدًا جدًا بحيث يشير إلى أسلوب الممارسة السيئ:

(1) لا يمكن للمبرمج أن يفترض بأمان أن جميع حالات انتهاك قيود الوسيطة تؤدي إلى IllegalArgumentException، لأن الغالبية العظمى من الفئات القياسية تستخدم هذا الاستثناء بدلاً من سلة المهملات إذا لم يكن هناك نوع أكثر تحديدًا من الاستثناءات المتاحة.إن محاولة تعيين جميع حالات انتهاكات قيود الوسيطات إلى IllegalArgumentException في واجهة برمجة التطبيقات (API) الخاصة بك لا تؤدي إلا إلى إحباط المبرمجين الذين يستخدمون فصولك، حيث تتبع المكتبات القياسية في الغالب قواعد مختلفة تنتهك قواعدك، وسيستخدمها معظم مستخدمي واجهة برمجة التطبيقات لديك أيضًا!

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

(3) يؤدي رسم الخرائط في الواقع إلى إنشاء خطر إخفاء الأخطاء:لتتمكن من تعيين انتهاكات قيد الوسيطة إلى IllegalArgumentException، ستحتاج إلى ترميز محاولة التقاط خارجية داخل كل أسلوب يحتوي على أي وسيطات مقيدة.ومع ذلك، فإن مجرد التقاط RuntimeException في كتلة الالتقاط هذه أمر غير وارد، لأن ذلك يخاطر بتعيين RuntimeExceptions الموثق الذي تم طرحه بواسطة أساليب التحرير المستخدمة داخل طريقتك إلى IllegalArgumentException، حتى لو لم يكن سببها انتهاكات قيود الوسيطة.لذلك يجب أن تكون محددًا للغاية، ولكن حتى هذا الجهد لا يحميك من الحالة التي تقوم فيها عن طريق الخطأ بتعيين استثناء غير موثق لوقت التشغيل لواجهة برمجة تطبيقات أخرى (أي.خطأ) في IllegalArgumentException لواجهة برمجة التطبيقات الخاصة بك.حتى التعيين الأكثر دقة يخاطر بإخفاء أخطاء البرمجة الخاصة بصانعي المكتبات الآخرين كانتهاكات لقيود الوسيطة لمستخدمي طريقتك، وهو ببساطة سلوك مضحك!

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

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

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

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

...مع قائمتين من الوسائط: "", null و null, ImmutableList.of().سيختبر أن كل من هذه المكالمات تلقي ما هو متوقع NullPointerException.لهذا التنفيذ، تمرير أ null القائمة تفعل ذلك لا ينتج NullPointerException.ومع ذلك، فإنه يحدث لإنتاج IllegalArgumentException لأن NullPointerTester يحدث لاستخدام سلسلة افتراضية من "".لو NullPointerTester يتوقع فقط NullPointerException ل null القيم، فإنه يمسك الخطأ.إذا كان يتوقع IllegalArgumentException, ، يفتقده.

كسؤال شخصي، يجب إغلاق هذا، لكنه لا يزال مفتوحًا:

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

استثناء NullPointer:لا رمي عمدا.يجب طرح NPEs فقط بواسطة الجهاز الظاهري عند إلغاء مرجع مرجع فارغ.يجب بذل كل جهد ممكن لضمان عدم رميها أبدًا.يجب استخدام @Nullable و@NotNull مع أدوات تحليل التعليمات البرمجية للعثور على هذه الأخطاء.

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

استثناء الدولة غير القانوني:يتم طرحها عندما يتم استدعاء دالة وتكون وسيطاتها إما غير متوقعة في وقت تمريرها أو غير متوافقة مع حالة الكائن الذي تكون الطريقة عضوًا فيه.

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

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

استثناء NullPointer:تعامل مع حالة Null أو قم بوضع تأكيد حتى لا يتم طرح NPE.إذا قمت بوضع تأكيد فهو مجرد واحد من النوعين الآخرين.إذا كان ذلك ممكنًا، تابع تصحيح الأخطاء كما لو كان التأكيد موجودًا في المقام الأول.

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

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

على أية حال، كانت وجهة نظره هي أنه يمكنك فقط نسخ IllegalArgumentAssertions في المكدس.لا توجد طريقة لنشر IllegalStateExceptions أو NullPointerExceptions في المكدس لأن لها علاقة بوظيفتك.

كنت أرغب في تمييز الوسيطات Null عن الوسيطات غير القانونية الأخرى، لذلك استنتجت استثناءً من IAE يسمى NullArgumentException.حتى دون الحاجة إلى قراءة رسالة الاستثناء، أعلم أنه تم تمرير وسيطة فارغة إلى إحدى الطرق ومن خلال قراءة الرسالة، أعرف الوسيطة التي كانت فارغة.ما زلت أتعرف على NullArgumentException باستخدام معالج IAE، ولكن في سجلاتي حيث يمكنني رؤية الفرق بسرعة.

الانقسام ...هل هي غير متداخلة؟فقط الأجزاء غير المتداخلة من الكل هي التي يمكنها إجراء الانقسام.كما اراه:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

بعض المجموعات تفترض ذلك null تم رفض استخدام NullPointerException بدلا من IllegalArgumentException.على سبيل المثال، إذا قمت بمقارنة مجموعة تحتوي على null إلى مجموعة ترفض null, ، سيتم استدعاء المجموعة الأولى containsAll من جهة أخرى وقبض عليه NullPointerException -- لكن لا IllegalArgumentException.(أنا أتطلع إلى تنفيذ AbstractSet.equals.)

يمكنك القول بشكل معقول أن استخدام الاستثناءات التي لم يتم التحقق منها بهذه الطريقة يعد نمطًا مضادًا مقارنة المجموعات التي تحتوي على null إلى المجموعات التي لا يمكن أن تحتوي null هو خطأ محتمل حقا يجب إنتاج استثناء، أو أن وضع null في مجموعة على الإطلاق هي فكرة سيئة.ومع ذلك، إلا إذا كنت على استعداد لقول ذلك equals يجب أن تطرح استثناءً في مثل هذه الحالة، فأنت عالق في تذكر ذلك NullPointerException مطلوب في ظروف معينة ولكن ليس في حالات أخرى.("IAE قبل NPE باستثناء بعد 'c'...")

تم طرح NullPointerException عند محاولة الوصول إلى كائن بمتغير مرجعي قيمته الحالية فارغة

يتم طرح IllegalArgumentException عندما يتلقى أسلوب ما وسيطة منسقة بشكل مختلف عما تتوقعه الطريقة

حسب السيناريو الخاص بك IllegalArgumentException هو الاختيار الأفضل، لأن null ليست قيمة صالحة للممتلكات الخاصة بك.

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

تعاريف الروابط إلى الاستثناءين أعلاه هي غير قانونية:يتم طرحه للإشارة إلى أنه تم تمرير وسيطة غير قانونية أو غير مناسبة إلى طريقة ما.استثناء NullPointer:يتم طرحها عندما يحاول أحد التطبيقات استخدام القيمة الخالية في حالة طلب كائن.

الفرق الكبير هنا هو أنه من المفترض استخدام IllegalArgumentException عند التحقق من صحة وسيطة الطريقة.من المفترض أن يتم استخدام NullPointerException عندما يتم "استخدام" كائن عندما يكون فارغًا.

آمل أن يساعد ذلك في وضع الاثنين في منظورهما الصحيح.

إذا كان "أداة ضبط"، أو في مكان ما أطلب من أحد الأعضاء استخدامه لاحقًا، فإنني أميل إلى استخدام IllegalArgumentException.

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

إذا قمت بتجاوز طريقة ما، فإنني أستخدم كل ما تستخدمه الطريقة المتجاوزة.

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

في هذه الحالة، ينقل IllegalArgumentException معلومات واضحة للمستخدم باستخدام واجهة برمجة التطبيقات الخاصة بك تفيد بأن " يجب ألا يكون فارغًا".كما أشار مستخدمو المنتدى الآخرون، يمكنك استخدام NPE إذا كنت تريد ذلك طالما أنك تنقل المعلومات الصحيحة إلى المستخدم باستخدام واجهة برمجة التطبيقات (API) الخاصة بك.

أسقط GaryF وtweakt مراجع "Effective Java" (التي أقسم بها) والتي توصي باستخدام NPE.والنظر في كيفية إنشاء واجهات برمجة التطبيقات الجيدة الأخرى هو أفضل طريقة لمعرفة كيفية إنشاء واجهة برمجة التطبيقات الخاصة بك.

مثال جيد آخر هو إلقاء نظرة على Spring APIs.على سبيل المثال، يحتوي org.springframework.beans.BeanUtils.instantiateClass(Constructor ctor, Object[] args) على السطر Assert.notNull(ctor, "Constructor must not be null").تتحقق طريقة org.springframework.util.Assert.notNull(Object object, String message) لمعرفة ما إذا كانت الوسيطة (الكائن) التي تم تمريرها فارغة أم لا، وإذا كانت كذلك فإنها تطرح IllegalArgumentException(message) جديدة والتي يتم اكتشافها بعد ذلك في المؤسسة. طريقة Springframework.beans.BeanUtils.instantiateClass(...).

إذا اخترت رمي ​​NPE وكنت تستخدم الوسيطة في طريقتك، فقد يكون التحقق بشكل صريح من وجود قيمة فارغة زائدًا ومكلفًا.أعتقد أن VM يفعل ذلك بالفعل من أجلك.

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