سؤال

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

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

على سبيل المثال:

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

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

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

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

المحلول

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

وبعبارة أخرى، هناك حالتان يظهر فيهما التحقق من القيمة الفارغة:

  1. عندما تكون القيمة null استجابة صالحة فيما يتعلق بالعقد؛و

  2. حيث أنه ليس ردا صالحا.

(٢) سهل.إما استخدام assert البيانات (التأكيدات) أو السماح بالفشل (على سبيل المثال، NullPointerException).التأكيدات هي ميزة Java غير مستخدمة بشكل كبير والتي تمت إضافتها في 1.4.بناء الجملة هو:

assert <condition>

أو

assert <condition> : <object>

أين <condition> هو تعبير منطقي و <object> هو كائن الذي toString() سيتم تضمين مخرجات الطريقة في الخطأ.

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

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

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

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

مع عدم المجموعات قد يكون الأمر أكثر صعوبة.اعتبر هذا كمثال:إذا كان لديك هذه الواجهات:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

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

الحل البديل هو عدم إرجاع قيمة فارغة مطلقًا واستخدام نمط كائن فارغ:

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

يقارن:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}

ل

ParserFactory.getParser().findAction(someInput).doSomething();

وهو تصميم أفضل بكثير لأنه يؤدي إلى تعليمات برمجية أكثر إيجازًا.

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

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

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

public Action findAction(final String userInput) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}

نصائح أخرى

إذا كنت تستخدم (أو تخطط لاستخدام) Java IDE مثل فكرة JetBrains IntelliJ, كسوف أو نتبيانز أو أداة مثل 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 @NotNull التطبيقات.

انظر مشاركة المدونة تعليقات توضيحية @Nullable/@NotNull أكثر مرونة وقابلة للتكوين.

إذا كانت القيم الخالية غير مسموح بها

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

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

وبعد ذلك، في بقية هذه الطريقة، ستعرف ذلك object هو ليس لاشيء.

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

مثال:

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

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

إذا سمح null

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

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

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


من النادر حقًا أن أستخدم المصطلح "if (object != null && ...".

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

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

يبدو المثال الذي قدمه Alex Miller كما يلي:

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

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


تحديث: ان اقتراح رسمي تم تقديم عامل التشغيل الآمن في Java 7 ضمن عملة المشروع. يختلف بناء الجملة قليلاً عن المثال أعلاه، ولكنه نفس الفكرة.


تحديث: لم يتم تحويل اقتراح المشغل الآمن إلى Project Coin.لذلك، لن ترى بناء الجملة هذا في Java 7.

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

يمكنك تكوين IDE الخاص بك لتحذيرك بشأن احتمال إلغاء المرجعية الخالية.على سبيل المثالفي الكسوف، انظر التفضيلات > Java > المترجم > الأخطاء/التحذيرات/التحليل الفارغ.

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

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

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

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

إذا كان عليك التعامل مع واجهة برمجة التطبيقات (API) التي قد تُرجع القيم الخالية, ، لا يمكنك فعل الكثير في Java.Xtend وGroovy لديهما عامل الفيس ?: و ال عامل التشغيل المرجعي الآمن ?., ، ولكن لاحظ أن هذا يُرجع قيمة فارغة في حالة وجود مرجع فارغ، لذلك فهو "يؤجل" المعالجة الصحيحة للمرجع الفارغ.

فقط لهذه الحالة -

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

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

سيؤدي إلى أ NullPointerException لو foo غير موجود.

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

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

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

إنهم يعملون هكذا:

كائن اختياري لنوع معين (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");

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

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

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

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

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

اعتمادًا على نوع الكائنات التي تقوم بالتحقق منها، قد تتمكن من استخدام بعض الفئات الموجودة في مشاعات Apache مثل: أباتشي كومونز لانج و مجموعات اباتشي المشاعات

مثال:

String foo;
...
if( StringUtils.isBlank( foo ) ) {
   ///do something
}

أو (حسب ما تحتاج إلى التحقق منه):

String foo;
...
if( StringUtils.isEmpty( foo ) ) {
   ///do something
}

فئة StringUtils هي واحدة فقط من بين العديد من الفئات؛هناك عدد لا بأس به من الفئات الجيدة في المشاعات التي تقوم بمعالجة آمنة خالية.

فيما يلي مثال لكيفية استخدام التحقق من الصحة في JAVA عند تضمين مكتبة apache(commons-lang-2.4.jar)

public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
    Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
    return read(new StringReader(xml), true, validationEventHandler);
}

وإذا كنت تستخدم Spring، فإن Spring لديه أيضًا نفس الوظيفة في حزمته، راجع Library(spring-2.4.6.jar)

مثال على كيفية استخدام هذه الفئة الثابتة من Spring(org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
  • إذا كنت تعتقد أن الكائن لا ينبغي أن يكون خاليًا (أو أنه خطأ)، فاستخدم التأكيد.
  • إذا كانت طريقتك لا تقبل المعلمات الفارغة، فقل ذلك في javadoc واستخدم التأكيد.

يجب عليك التحقق من الكائن != null فقط إذا كنت تريد التعامل مع الحالة التي قد يكون فيها الكائن فارغًا...

هناك اقتراح لإضافة تعليقات توضيحية جديدة في Java7 للمساعدة في المعلمات الفارغة/غير الفارغة:http://tech.puredanger.com/java7/#jsr308

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

يوفر إطار عمل مجموعات 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();

في بعض الأحيان، يكون لديك توابع تعمل وفقًا لمعلماتها التي تحدد عملية متماثلة:

a.f(b); <-> b.f(a);

إذا كنت تعلم أن b لا يمكن أن يكون فارغًا أبدًا، فيمكنك فقط تبديله.هو الأكثر فائدة للمساواة:بدلاً من foo.equals("bar"); من الأفضل أن تفعل "bar".equals(foo);.

بدلاً من نمط الكائن الفارغ - الذي له استخداماته - يمكنك التفكير في المواقف التي يكون فيها الكائن الفارغ خطأً.

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

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

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

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

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

يصبح

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

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

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

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

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

    getPhotoOfThePerson(me.getGirlfriend())
    

    ويتناسب مع Java API الجديد القادم (نتطلع)

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

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

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

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

    /**
     * @return photo or null
     */
    

    أو

    /**
     * @return photo, never null
     */
    
  2. هذه حالة نظرية إلى حد ما، وفي معظم الحالات، يجب أن تفضل واجهة برمجة تطبيقات Java null Safe (في حالة إصدارها خلال 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).ال تتناسب واجهة برمجة التطبيقات Java Null-safe الجديدة بشكل أفضل هنا لتحديد ما يعنيه وما لا يعنيه أن تتم تهيئته بشكل انتقائي لتكون سريعة الفشل في حالة وجود أخطاء مبرمج.

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

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

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

    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;
    }
    

    بس.بالنسبة لأولئك الذين يسارعون إلى التصويت السلبي (وليسوا سريعين في قراءة الوثائق) أود أن أقول إنني لم أكتشف مطلقًا استثناء المؤشر الفارغ (NPE) في حياتي.ولكن هذا الاحتمال كان مصممة عمدا بواسطة منشئي Java لأن 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 (لكي تحدد وتستخدم المسجل المفضل لديك أو أي آلية إعلام أخرى).إذا لم يتم تعيينها، ThreadGroup#uncaughtException سيتم طباعة Stacktrace لخطأ النظام.يجب على المرء مراقبة سجل أخطاء التطبيق وفتح مشكلة Jira لكل استثناء لم تتم معالجته وهو في الواقع خطأ في التطبيق.يجب على المبرمج إصلاح الخلل في مكان ما في عناصر التهيئة.

في النهاية، الطريقة الوحيدة لحل هذه المشكلة تمامًا هي استخدام لغة برمجة مختلفة:

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

"مشكلة" شائعة في جافا بالفعل.

أولاً رأيي في هذا:

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

لذلك، IMHO, null يجب أن يكون خطأً فادحًا يمنع تنفيذًا إضافيًا (أي عندما لا تكون القيمة null قيمة صالحة).

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

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

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

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

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

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

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

void validate() throws ValidationException;

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

"تمت مصادفة قيمة وسيطة غير قانونية فارغة للمعلمة [الخطط]"

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

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

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

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

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

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

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

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

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

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

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



    .....
}

فقط لا تستخدم أبدًا null.لا تسمح بذلك.

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

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

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

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

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

تحتوي Guava، وهي مكتبة أساسية مفيدة جدًا من Google، على واجهة برمجة تطبيقات لطيفة ومفيدة لتجنب القيم الخالية.وجدت شرح الاستخدام وتجنب Null مفيد جدا.

كما هو موضح في الويكي :

Optional<T> هي وسيلة لاستبدال مرجع t لاغال مع قيمة غير فنية.قد يحتوي اختياري إما على مرجع T غير الفني (وفي هذه الحالة نقول أن المرجع "موجود") ، أو قد لا يحتوي على أي شيء (وفي هذه الحالة نقول إن المرجع "غائب").لا يُقال أبدًا أن "تحتوي على فارغ".

الاستخدام:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

هذه مشكلة شائعة جدًا لكل مطور Java.لذا، هناك دعم رسمي في Java 8 لمعالجة هذه المشكلات دون فوضى التعليمات البرمجية.

لقد تم تقديم جافا 8 java.util.Optional<T>.إنها حاوية قد تحتوي أو لا تحتوي على قيمة غير فارغة.لقد وفرت Java 8 طريقة أكثر أمانًا للتعامل مع كائن قد تكون قيمته فارغة في بعض الحالات.وهي مستوحاة من أفكار هاسكل و سكالا.

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

في المثال أعلاه لدينا مصنع للخدمات المنزلية يقوم بإرجاع مقبض إلى العديد من الأجهزة المتوفرة في المنزل.لكن هذه الخدمات قد تكون أو لا تكون متاحة/عاملة؛فهذا يعني أنه قد يؤدي إلى NullPointerException.بدلاً من إضافة قيمة خالية if شرط قبل استخدام أي خدمة، دعونا نلخصها في اختياري<خدمة>.

الالتفاف على الخيار<T>

دعونا نفكر في طريقة للحصول على مرجع للخدمة من المصنع.بدلاً من إرجاع مرجع الخدمة، قم بتضمينه بـ اختياري.فهو يتيح لمستخدم واجهة برمجة التطبيقات (API) معرفة أن الخدمة التي تم إرجاعها قد تكون أو لا تكون متاحة/وظيفية، ويتم استخدامها بشكل دفاعي

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

كما ترى Optional.ofNullable() يوفر طريقة سهلة للحصول على المرجع ملفوفًا.هناك طرق أخرى للحصول على مرجع اختياري أيضًا Optional.empty() & Optional.of().أحدهما لإرجاع كائن فارغ بدلاً من إعادة ضبطه فارغًا والآخر لالتفاف كائن غير فارغ، على التوالي.

إذًا كيف يساعد ذلك على تجنب التحقق الفارغ؟

بمجرد الانتهاء من تغليف كائن مرجعي، يوفر الخيار الاختياري العديد من الأساليب المفيدة لاستدعاء الأساليب على مرجع مغلف بدون NPE.

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

يستدعيOptional.ifPresent المستهلك المحدد بمرجع إذا كانت قيمة غير فارغة.خلاف ذلك، فإنه لا يفعل شيئا.

@FunctionalInterface
public interface Consumer<T>

يمثل عملية تقبل وسيطة إدخال واحدة ولا تُرجع أي نتيجة.على عكس معظم الواجهات الوظيفية الأخرى، من المتوقع أن يعمل المستهلك من خلال الآثار الجانبية.إنه نظيف للغاية وسهل الفهم.في مثال الكود أعلاه، HomeService.switchOn(Service) يتم استدعاؤه إذا كان مرجع الحجز الاختياري غير فارغ.

نستخدم المشغل الثلاثي في ​​كثير من الأحيان للتحقق من الحالة الخالية وإرجاع قيمة بديلة أو قيمة افتراضية.يوفر الخيار الاختياري طريقة أخرى للتعامل مع نفس الحالة دون التحقق من القيمة الخالية.يتم إرجاعOptional.orElse(defaultObj)‎ defaultObj إذا كان الخيار الاختياري يحتوي على قيمة فارغة.دعونا نستخدم هذا في نموذج التعليمات البرمجية لدينا:

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

الآن HomeServices.get() يفعل نفس الشيء، ولكن بطريقة أفضل.إنه يتحقق مما إذا كانت الخدمة قد تمت تهيئتها بالفعل أم لا.إذا كان الأمر كذلك، قم بإرجاع نفس الشيء أو إنشاء خدمة جديدة جديدة.يساعد الاختياري<T>.orElse(T) على إرجاع قيمة افتراضية.

أخيرًا، إليك رمز NPE الخاص بنا بالإضافة إلى رمز التحقق الخالي من القيمة:

import java.util.Optional;
public class HomeServices {
    private static final int NOW = 0;
    private static Optional<HomeServices> service;

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

public Optional<Service> getRefrigertorControl() {
    Service s = new  RefrigeratorService();
    //...
    return Optional.ofNullable(s);
}

public static void main(String[] args) {
    /* Get Home Services handle */
    Optional<HomeServices> homeServices = HomeServices.get();
    if(homeServices != null) {
        Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
        refrigertorControl.ifPresent(HomeServices::switchItOn);
    }
}

public static void switchItOn(Service s){
         //...
    }
}

المشاركة كاملة هي NPE بالإضافة إلى رمز التحقق المجاني Null … حقًا؟.

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

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

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

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

والآن إلى الجواب:

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

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

بايت!

ربما يكون أفضل بديل لـ 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);

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

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

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

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

إذن لا فرق بين:

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 أو استخدم مكتبات أكثر تطوراً مثل مدقق السبات.

مجرد عينة:

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;

   // ...
}

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

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

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

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

يجدر النظر في مثل هذه الحالات لتجنب النتائج السخيفة.

  1. لا تقم مطلقًا بتهيئة المتغيرات إلى قيمة خالية.
  2. إذا لم يكن (1) ممكنًا، فقم بتهيئة كافة المجموعات والمصفوفات لتفريغ المجموعات/المصفوفات.

قم بذلك باستخدام التعليمات البرمجية الخاصة بك ويمكنك تجنب != عمليات التحقق الخالية.

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

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

هناك حمل بسيط في هذا، ولكن الأمر يستحق ذلك للحصول على تعليمات برمجية أنظف وأقل من NullPointerExceptions.

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

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

النهج 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;
}
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top