java - شرح - null pointer exception in android حل مشكلة




تجنب!=بيانات فارغة (20)

أنا استخدم object != null الكثير لتجنب NullPointerException .

هل هناك بديل جيد لهذا؟

فمثلا:

if (someobject != null) {
    someobject.doCalc();
}

هذا يتجنب NullPointerException ، عندما يكون غير معروف إذا كان الكائن null أم لا.

لاحظ أن الإجابة المقبولة قد تكون غير محدثة ، راجع https://stackoverflow.com/a/2386013/12943 للحصول على مقاربة أحدث.


إذا لم يتم السماح بالقيم الخالية

إذا تم استدعاء الطريقة الخاصة بك خارجيًا ، فابدأ بشيء مثل هذا:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

ثم ، في بقية هذه الطريقة ، ستعرف أن object ليس خاليًا.

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

مثال:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

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

إذا سمح باطل

هذا يعتمد حقا. إذا وجدت أنني غالباً ما أقوم بشيء كالتالي:

if (object == null) {
  // something
} else {
  // something else
}

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

من النادر في الواقع بالنسبة لي استخدام المصطلح " if (object != null && ... ".

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


إذا لم يتم السماح بالقيم غير المحددة:

قد تقوم بتكوين IDE الخاص بك لتحذيرك من إلغاء التراجع. مثال في Eclipse ، راجع تفضيلات> Java> مترجم> أخطاء / تحذيرات / تحليل فارغ .

إذا تم السماح بالقيم غير المحددة:

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

  • تم ذكره بوضوح في API ما إذا كان هناك مدخلات أو مخرجات موجودة أم لا.
  • يفرض عليك المحول البرمجي معالجة الحالة "غير المحددة".
  • الخيار هو monad ، لذلك ليس هناك حاجة لفحص باطل مطول ، فقط استخدم map / foreach / getOrElse أو أداة دمج مماثلة لاستخدام القيمة (example) بأمان.

يحتوي Java 8 على فئة Optional مدمجة (مستحسن)؛ للإصدارات السابقة ، هناك بدائل للمكتبة ، على سبيل المثال Option Guava الخاص Guava Optional أو FunctionalJava . ولكن مثل العديد من أنماط الأنماط الوظيفية ، فإن استخدام الخيار في Java (حتى 8) يؤدي إلى بعض المقاسات ، والتي يمكنك تقليلها باستخدام لغة JVM أقل مطولاً ، مثل Scala أو Xtend.

إذا كان عليك التعامل مع واجهة برمجة التطبيقات (API) التي قد تعيد القيمة الفارغة ، فلا يمكنك فعل الكثير في Java. لدى Xtend و Groovy مشغل Elvis ?: ومشغل dereference آمن تمامًا ?. ولكن لاحظ أن هذا إرجاع null في حالة مرجع فارغة ، لذلك فقط "defers" معالجة المناسبة من null.


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


إذا كنت تستخدم (أو تخطط لاستخدام) Java IDE مثل JetBrains IntelliJ IDEA أو Eclipse أو Netbeans أو أداة مثل findbugs ، فيمكنك استخدام التعليقات التوضيحية لحل هذه المشكلة.

في الأساس ، لديك @Nullable و @NotNull .

يمكنك استخدام الطريقة والمعلمات ، مثل:

@NotNull public static String helloWorld() {
    return "Hello World";
}

أو

@Nullable public static String helloWorld() {
    return "Hello World";
}

لن يتم ترجمة المثال الثاني (في IntelliJ IDEA).

عند استخدام الدالة helloWorld() الأولى في جزء آخر من التعليمات البرمجية:

public static void main(String[] args)
{
    String result = helloWorld();
    if(result != null) {
        System.out.println(result);
    }
}

الآن سوف يخبرك المترجم IntelliJ IDEA أن الشيك عديم الفائدة ، لأن الدالة helloWorld() لن تعود null .

باستخدام المعلمة

void someMethod(@NotNull someParameter) { }

إذا كتبت شيئًا مثل:

someMethod(null);

هذا لن تجميع.

المثال الأخير باستخدام @Nullable

@Nullable iWantToDestroyEverything() { return null; }

فعل هذا

iWantToDestroyEverything().something();

ويمكنك التأكد من أن هذا لن يحدث. :)

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

في IntelliJ IDEA 10.5 وما @Nullable ، أضافوا دعمًا لأي @Nullable @NotNull أخرى.

راجع مشاركة المدونة المزيد من التعليقات التوضيحية المرنة وغير القابلة للتضمين @ Nullable / @ NotNull .


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

عند طرح الاستثناء ، قم بفحص تتبع المكدس والعمل من خلال الخطأ.


فقط لهذا الوضع -

عدم التحقق مما إذا كان المتغير فارغًا قبل استدعاء طريقة يساوي (مثال للمقارنة بين سلسلة):

if ( foo.equals("bar") ) {
 // ...
}

سيؤدي إلى NullPointerException إذا كان foo غير موجود.

يمكنك تجنب ذلك إذا قارنت String الخاصة بك مثل هذا:

if ( "bar".equals(foo) ) {
 // ...
}

مع Java 8 تأتي فئة java.util.Optional الجديدة التي يمكن حلها بشكل java.util.Optional للجدل بعض من المشكلة. يمكن للمرء على الأقل أن يقول أنه يحسن قراءة الشفرة ، وفي حالة واجهات برمجة التطبيقات العامة ، يجعل عقد API أكثر وضوحًا لمطوِّر العميل.

يعملون على هذا النحو:

يتم إنشاء كائن اختياري لنوع معين ( Fruit ) كنوع الإرجاع للطريقة. يمكن أن تكون فارغة أو تحتوي على كائن Fruit :

public static Optional<Fruit> find(String name, List<Fruit> fruits) {
   for (Fruit fruit : fruits) {
      if (fruit.getName().equals(name)) {
         return Optional.of(fruit);
      }
   }
   return Optional.empty();
}

انظر الآن إلى هذا الرمز الذي نبحث فيه عن قائمة من Fruit ( fruits ) لمثيل فاكهة معين:

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

يمكنك استخدام عامل map() لإجراء عملية حساب - أو استخراج قيمة من - كائن اختياري. يتيح لك orElse() إمكانية توفير قيم احتياطية للقيم المفقودة.

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

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

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

بالطبع يمكن أيضًا استخدام " Optional كوسيطة أسلوب ، ربما طريقة أفضل للإشارة إلى الحجج الاختيارية من 5 أو 10 أساليب التحميل الزائد في بعض الحالات.

تقدم Optional طرقًا مريحة أخرى ، مثل orElse التي تسمح باستخدام القيمة الافتراضية ، وإذا ifPresent تعمل مع تعبيرات لامدا .

أدعوك لقراءة هذه المقالة (المصدر الرئيسي لكتابة هذه الإجابة) والتي تم شرحها بشكل جيد في NullPointerException (وفي مؤشر null pointer) بالإضافة إلى الحل (الجزئي) الذي يتم إحضاره بواسطة Optional : Java Optional Objects .


نجاح باهر ، أكره أن أضيف إجابة أخرى عندما يكون لدينا 57 طريقة مختلفة للتوصية NullObject pattern ، لكني أعتقد أن بعض الأشخاص المهتمين بهذا السؤال قد يرغبون في معرفة أن هناك اقتراحًا على الطاولة لـ Java 7 لإضافة "null" التعامل الآمن " - بناء مبسط لمنطق if-not- equalle -null.

المثال الذي قدمه أليكس ميلر يبدو كالتالي:

public String getPostcode(Person person) {  
  return person?.getAddress()?.getPostcode();  
}  

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

تحديث: تم proposed لمشغل آمن في Java 7 في إطار Project Coin. البنية تختلف قليلاً عن المثال أعلاه ، ولكنها نفس الفكرة.

تحديث: لم يعمل مقترح مشغل null-safe في Project Coin. لذلك ، لن ترى هذه الصيغة في Java 7.


يوفر إطار مجموعات Google طريقة جيدة وأنيقة لتحقيق الاختيار الفارغ.

هناك طريقة في فصل مكتبة مثل هذا:

static <T> T checkNotNull(T e) {
   if (e == null) {
      throw new NullPointerException();
   }
   return e;
}

والاستخدام (مع import static ):

...
void foo(int a, Person p) {
   if (checkNotNull(p).getAge() > a) {
      ...
   }
   else {
      ...
   }
}
...

أو في المثال الخاص بك:

checkNotNull(someobject).doCalc();

المشترك "مشكلة" في جاوة في الواقع.

أولا ، أفكاري حول هذا:

أعتقد أنه من السيئ أن "أكل" شيء عندما تم تمرير NULL حيث NULL ليست قيمة صالحة. إذا كنت لا تخرج من هذه الطريقة بنوع من الخطأ ، فهذا يعني أنه لم يحدث أي خطأ في طريقتك وهذا غير صحيح. ثم ربما ترجع null في هذه الحالة ، وفي طريقة الاستلام ، يمكنك التحقق مرة أخرى من قيمة null ، ولا تنتهي أبدًا ، وينتهي الأمر بـ "if! = null" ، وما إلى ذلك.

لذلك ، يجب أن يكون خطأ IMHO ، خطأ فادحًا يمنع حدوث المزيد من التنفيذ (أي ، حيث لا توجد قيمة فارغة).

طريقة حل هذه المشكلة هي:

أولاً ، أتبع هذه الاتفاقية:

  1. جميع الطرق العامة / واجهة برمجة التطبيقات تتحقق دائمًا من وسيطاتها للقيمة الخالية
  2. لا تتحقق كافة الطرق الخاصة للقيمة الفارغة نظرًا لأنها أساليب يتم التحكم فيها (فقط دعها تموت مع استثناء nullpointer في حالة عدم التعامل معها أعلاه)
  3. الطرق الأخرى التي لا تحقق من وجود null هي أساليب الاستخدام. فهي عامة ، ولكن إذا كنت تسميها لسبب ما ، فأنت تعرف ما هي المعلمات التي تمر بها. هذا مثل محاولة غلي الماء في الغلاية بدون توفير الماء ...

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

ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

لاحظ أن addParam () تقوم بإرجاع self ، بحيث يمكنك إضافة المزيد من المعلمات للتحقق.

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

void validate() throws ValidationException;

ستحتوي الرسالة على النص التالي إذا ، على سبيل المثال ، "خطط" خالية:

" تمت مواجهة قيمة وسيطة غير مسموح بها للمعلمة [خطط] "

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

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

بهذه الطريقة ، الشفرة نظيفة وسهلة الصيانة وقابلة للقراءة.


هذا هو الخطأ الأكثر شيوعًا الذي يحدث لمعظم المطورين.

لدينا عدد من الطرق للتعامل مع هذا.

النهج 1:

org.apache.commons.lang.Validate //using apache framework

notNull (كائن كائن ، رسالة سلسلة)

المقاربة 2:

if(someObject!=null){ // simply checking against null
}

المقاربة 3:

@isNull @Nullable  // using annotation based validation

المنهج 4:

// by writing static method and calling it across whereever we needed to check the validation

static <T> T isNull(someObject e){  
   if(e == null){
      throw new NullPointerException();
   }
   return e;
}

هل يمكن أن أجيب عليه بشكل أكثر عمومية!

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

لذلك لا يوجد فرق بين:

if(object == null){
   //you called my method badly!

}

أو

if(str.length() == 0){
   //you called my method badly again!
}

كلاهما يريد التأكد من أننا تلقينا معلمات صالحة ، قبل القيام بأي وظائف أخرى.

كما ذكر في بعض الإجابات الأخرى ، لتجنب المشاكل المذكورة أعلاه يمكنك اتباع التصميم حسب نمط العقد . يرجى الاطلاع على http://en.wikipedia.org/wiki/Design_by_contract .

لتنفيذ هذا النمط في جافا ، يمكنك استخدام تعليقات جافا الأساسية مثل javax.annotation.NotNull أو استخدام مكتبات أكثر تعقيدًا مثل Hibernate Validator .

مجرد عينة:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

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

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

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

أنا أحب مقالات من نات برايس. وهنا الروابط:

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


بالإضافة إلى استخدام assertيمكنك استخدام ما يلي:

if (someobject == null) {
    // Handle null here then move on.
}

هذا أفضل قليلاً من:

if (someobject != null) {
    .....
    .....



    .....
}

ربما يكون أفضل بديل لـ Java 8 أو الأحدث هو استخدام Optionalالفصل.

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

هذا مفيد خصوصا لسلاسل طويلة من القيم الخالية الممكنة. مثال:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

مثال على كيفية رمي الاستثناء في فارغة:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

قدمت Java 7 Objects.requireNonNullالطريقة التي يمكن أن تكون في متناول اليد عندما ينبغي التحقق من وجود شيء لعدم البطلان. مثال:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();

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

  1. السماح للاستثناءات من خلال تموج من خلال - قبض عليهم في "حلقة رئيسية" أو في روتين إدارة أخرى.

    • تحقق من وجود حالات خطأ والتعامل معها بشكل مناسب

بالتأكيد ألقي نظرة على برمجة Aspect Oriented Programming أيضًا - فلديهم طرق أنيقة لإدخالها if( o == null ) handleNull()في كودك البايت.


لا تعتبر Null مشكلة. وهو جزء لا يتجزأ من مجموعة complete أدوات النمذجة. يهدف البرنامج إلى نمذجة تعقيد العالم والعبء الذي يتحمل عبئه. يشير Null إلى "No data" أو "Unknown" في Java وما شابه. لذلك من المناسب استخدام الفراغات لهذه الأغراض. لا أفضّل نمط "الكائن الخالي" ؛ أعتقد أنه يرتفع " من سيحرس مشكلة الأوصياء ".
إذا سألتني ما هو اسم صديقتي سأخبرك أنه ليس لدي أي صديقة. في لغة جافا سأعود فارغة. قد يكون البديل هو إلقاء استثناء مفيد للإشارة إلى بعض المشاكل التي لا يمكن (أو عدمر تريد أن تكون) حل هناك وتفويض ذلك في مكان ما أعلى في المكدس لإعادة المحاولة أو تقرير خطأ الوصول إلى البيانات للمستخدم.

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

    public Photo getPhotoOfThePerson(Person person) {
        if (person == null)
            return null;
        // Grabbing some resources or intensive calculation
        // using person object anyhow.
    }
    

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

    getPhotoOfThePerson(me.getGirlfriend())
    

    وتناسبها مع واجهة برمجة تطبيقات جافا الجديدة (تتطلع إلى الأمام)

    getPhotoByName(me.getGirlfriend()?.getName())
    

    في حين أنه "تدفق العمل العادي" بدلا من العثور على صورة مخزنة في DB لشخص ما ، اعتدت على استخدام أزواج مثل أدناه لبعض الحالات الأخرى

    public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException
    public static MyEnum parseMyEnumOrNull(String value);
    

    ولا تكره الكتابة <alt> + <shift> + <j>(توليد javadoc في Eclipse) وكتابة ثلاث كلمات إضافية لك API العام. سيكون هذا أكثر من كافٍ للجميع باستثناء أولئك الذين لا يقرأون الوثائق.

    /**
     * @return photo or null
     */
    

    أو

    /**
     * @return photo, never null
     */
    
  2. هذه هي الحالة النظرية وفي معظم الحالات يجب عليك أن تختار واجهة برمجة تطبيقات جافا جافا (في حال سيتم إصدارها في 10 سنوات أخرى) ، ولكن NullPointerExceptionهي فئة فرعية من Exception. هكذا هو شكل من أشكال Throwableذلك يشير إلى الشروط التي قد يرغب التطبيق المعقول للقبض عليها ( javadoc )! لاستخدام الميزة الأولى من الاستثناءات وشفرة معالجة الأخطاء المنفصلة من الكود "العادي" ( وفقًا لمبدعين جافا ) ، من المناسب ، بالنسبة لي ، أن يتم الإمساك بها NullPointerException.

    public Photo getGirlfriendPhoto() {
        try {
            return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
        } catch (NullPointerException e) {
            return null;
        }
    }
    

    يمكن أن تنشأ الأسئلة:

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

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

    Q. هذا الأسلوب له عقوبة الأداء بسبب محاولة إغلاق الإغلاق.
    يجب أن تكون البرامج سهلة الفهم والتعديل أولاً. فقط بعد هذا ، يمكن للمرء أن يفكر في الأداء ، وفقط إذا لزم الأمر! وحيث الحاجة! ( source ) ، وغيرها الكثير).

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

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }
    

    PPS. لأولئك سريع لتخفيض (وليس بسرعة لقراءة الوثائق) أود أن أقول أنني لم القبض على استثناء مؤشر null (NPE) في حياتي. ولكن تم تصميم هذا الاحتمال عن قصد من قبل منشئي جافا لأن NPE هو فئة فرعية من Exception. لدينا سابقة في التاريخ جافا عندما ThreadDeathهو Errorليس لأنه هو في الواقع خطأ التطبيق، ولكن فقط لأنه لم يكن يقصد به أن تكون اشتعلت! كم NPE يناسب ليكون Errorمن ThreadDeath! لكنها ليست كذلك.

  3. تحقق من "لا توجد بيانات" فقط إذا كان منطق الأعمال يشير إلى ذلك.

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }
    

    و

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }
    

    إذا لم تتم تهيئة appContext أو dataSource غير مهيأ وقت التشغيل سيؤدي NullPointerException إلى Thread.defaultUncaughtExceptionHandler مؤشر الترابط الحالي وسيتم معالجته بواسطة Thread.defaultUncaughtExceptionHandler (لتتمكن من تحديد واستخدام Thread.defaultUncaughtExceptionHandler المفضلة لديك أو آلية إخطار أخرى). في حالة عدم ThreadGroup#uncaughtException ، ThreadGroup#uncaughtException بطباعة stacktrace إلى نظام err. ينبغي للمرء أن يراقب سجل خطأ التطبيق ويفتح قضية جيرا لكل استثناء غير معالج وهو في الواقع خطأ في التطبيق. يجب على المبرمج إصلاح الخطأ في مكان ما في أشياء التهيئة.


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

NullPointerExceptionهو الاستثناء وقت التشغيل الذي يعني خطأ المطورين ومع الخبرة الكافية يخبرك بالضبط أين هو الخطأ.

الآن للإجابة:

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

بالطبع ، التجربة هي أفضل طريقة لفهم وتطبيق هذا الاقتراح.

بايت!


يحتوي Java 7 على java.util.Objectsفئة أداة مساعدة جديدة توجد بها requireNonNull()طريقة. كل هذا هو رمي إذا NullPointerExceptionكانت حجته خالية ، لكنها تقوم بتنظيف التعليمات البرمجية قليلاً. مثال:

Objects.requireNonNull(someObject);
someObject.doCalc();

تكون الطريقة مفيدة للغاية checking قبل تعيينها في مُنشئ ، حيث يمكن لكل استخدام منها حفظ ثلاثة أسطر من الكود:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

يصبح

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}

public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}






null