كيفية إظهار ما إذا كانت الطريقة قد ترجع فارغة

StackOverflow https://stackoverflow.com/questions/411447

  •  03-07-2019
  •  | 
  •  

سؤال

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

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

بعض الطرق التي يمكنني التفكير فيها:

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

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

لماذا لا يوجد شيء من هذا القبيل:

public notnull Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

الملخص و الاستنتاج

هناك طرق عديدة للتعبير عن العقد:

  • إذا كان IDE الخاص بك يدعمه (مثل IntelliJ)، فمن الأفضل استخدام تعليق توضيحي مثل @NotNull لأنه مرئي للمبرمج ويمكن استخدامه للتحقق الآلي من وقت الترجمة.هناك البرنامج المساعد للكسوف لإضافة دعم لهذه، لكنه لم ينجح بالنسبة لي.
  • إذا لم يكن هذا خيارًا، فاستخدم الأنواع المخصصة مثل Option<T> أو NotNull<T>, ، مما يضيف الوضوح والتحقق من وقت التشغيل على الأقل.
  • بأي حال من الأحوال، فإن توثيق العقد في JavaDoc لا يضر أبدًا، بل ويساعد في بعض الأحيان.
  • استخدام أسماء الطرق لتوثيق البطلان لم يتم اقتراح القيمة المرجعة من قبل أي شخص غيري، وعلى الرغم من أنها قد تكون مطولة للغاية وليست مفيدة دائمًا، إلا أنني ما زلت أعتقد في بعض الأحيان أن لها مزاياها أيضًا.
هل كانت مفيدة؟

المحلول

سؤال متابعة جيد جدًا.أنا أعتبر null قيمة خاصة حقًا، وإذا كانت الطريقة قد تعود null يجب أن يتم توثيقه بوضوح في Javadoc عندما يحدث ذلك (@return some value ..., or null if ...).عندما أقوم بالبرمجة، فأنا أكون دفاعيًا، وأفترض أن إحدى الطرق قد تعود null إلا إذا كنت مقتنعًا بأنه لا يمكن ذلك (على سبيل المثال، لأن Javadoc قال ذلك.)

أدرك الناس أن هذه مشكلة، والحل المقترح هو استخدام التعليقات التوضيحية لتوضيح النية بطريقة يمكن التحقق منها تلقائيًا.يرى جي إس آر 305:التعليقات التوضيحية لاكتشاف عيوب البرامج, JSR 308:شروح على أنواع جافا و JetBrain's Nullable How-To.

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

@NotNull
public Object methodWhichCannotReturnNull(int i) throws Exception
{
    return null; // this would lead to a compiler error!
}

نصائح أخرى

يمكنك استخدام ال Option type، وهو يشبه إلى حد كبير القائمة التي تحتوي على صفر أو عنصر واحد.نوع العودة من Option<Object> يشير إلى أن الطريقة قد تُرجع ملفًا Object, أو قد تُرجع قيمة خاصة من النوع None.يعد هذا النوع بديلاً لاستخدام القيمة الخالية مع عمليات فحص أفضل للنوع.

مثال:

public Option<Integer> parseInt(String s) {
   try {
      return Option.some(Integer.parseInt(s));
   }
   catch (Exception e) {
      return Option.none();
   }
}

إذا كنت تستخدم هذا باستمرار، فيمكنك تشغيل تحذيرات IDE الخالية، أو مجرد استخدام grep لـ null والتي لا ينبغي أن تظهر في التعليمات البرمجية الخاصة بك على الإطلاق إذا كنت تستخدمها Option.none() في كل مكان تستخدمه عادةً أ null حرفي.

Option يأتي بشكل قياسي مع Scala، ويسمى Maybe في هاسكل.الرابط أعلاه هو لمكتبة تسمى جافا الوظيفية يتضمن ذلك.هذا الإصدار ينفذ Iterable واجهة، ولها أساليب أحادية تتيح لك إنشاء الأشياء بشكل جيد.على سبيل المثال، لتوفير قيمة افتراضية قدرها 0 في حالة None:

int x = optionalInt.orSome(0);

ويمكنك استبدال هذا ...

if (myString != null && !"".equals(myString))

...مع هذا، إذا كان لديك Option<String>...

for (String s : myOptionString)

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

أرى ثلاثة خيارات:

  1. انتظر دعم اللغة للتعبير عنه (على سبيل المثال.ال ج#؟! شيء)
  2. استخدم Aspect Orientation لإنشاء امتدادات اللغة الخاصة بك للتعبير عنها
  3. استخدم نوعًا مخصصًا للتعبير عنه
  4. (ولكنه يعتمد على تعاون المطورين) استخدم نظام تسمية للإشارة إليه

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

ومن ناحية أخرى، أعترف بأنني لا أرى أن العدم شيء يخيف.هناك مواقف يكون فيها "لا أحد في المنزل" حالة ذات معنى (على الرغم من أن تقنية Null Object لها أيضًا قيمة حقيقية هنا).

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

هل ألقيت نظرة على المواصفات #?

يمكنك كتابة التعليق التوضيحي الخاص بك (Java) أو السمة (C#) للإشارة إلى أن القيمة المرجعة قد تكون فارغة.لن يتحقق أي شيء تلقائيًا (على الرغم من أن .NET 4.0 سيحتوي على عقود الكود لهذا النوع من الأشياء) ولكنها على الأقل ستكون بمثابة توثيق.

هناك بعض الدعم ل التعليق التوضيحي @Nullable وNotNull في IntelliJ IDEA.هناك أيضًا بعض الحديث عن إضافة تلك التعليقات التوضيحية (أو ميزة مشابهة) إلى Java 7.لسوء الحظ، لا أعرف إلى أي مدى وصل ذلك أو ما إذا كان لا يزال على المسار الصحيح على الإطلاق.

ربما يمكنك تحديد فئة عامة تسمى "NotNull"، بحيث تكون طريقتك مثل:

public NotNull<Object> methodWhichCannotReturnNull(int i) throws Exception
{
   // the following would lead to a run-time error thown by the
   // NotNull constructor, if it's constructed with a null value
   return new NotNull<Object>(null);
}

لا يزال هذا فحصًا لوقت التشغيل (وليس وقت الترجمة)، ولكن:

  • تم طرحه في تنفيذ الطريقة (ليس خطأ في رمز الاتصال)
  • إنه توثيق ذاتي (يعرف المتصل أنه يحصل على NotNull<T> كنوع العودة)

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

إذا كنت تستخدم Java 5+، فيمكنك استخدام تعليق توضيحي مخصص، على سبيل المثال.@MayReturnNull

تحديث

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

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

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

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