كيف تتوقف عن التحقق من null في Java دون أن تصاب بالجنون

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لعنة null: لماذا نكتب نفس الشيء مرارًا وتكرارًا؟

\n\n

إذا كنت تكتب بلغة Java لأكثر من أسبوع، فبالتأكيد واجهت NullPointerException. وعلى الأرجح، كان رد فعلك الأول: "آه، فقط يجب التحقق!". هكذا تولد أميال من الكود مثل:

\n\n
if (user != null) {\n    if (user.getAddress() != null) {\n        String city = user.getAddress().getCity();\n        if (city != null) {\n            System.out.println(city.toUpperCase());\n        }\n    }\n}\n
\n\n

هذا الكود يعمل. لكنه قبيح. يحول قراءة المنطق إلى عذاب، والصيانة إلى كابوس. سؤال "How do I avoid checking for nulls in Java?" على Stack Overflow جمع آلاف المشاهدات ليس من قبيل الصدفة. كل مطور Java يطرحه عاجلاً أم آجلاً.

\n\n

الخبر السار: تجنب التحقق من null ليس ممكنًا فحسب، بل ضروري. Java ليست JavaScript، ولدينا أدوات لكتابة كود نظيف وآمن بدون هياكل "دفاعية". دعنا نستعرضها جميعًا - من المجموعة الأساسية إلى التقنيات المتقدمة.

\n\n

1. Optional<T> - حليفك الرئيسي

\n\n

منذ Java 8، لدينا Optional. هو حاوية يمكن أن تحتوي على قيمة أو تكون فارغة. صُمم حرفيًا لـ تجنب التحقق من null وجعل الكود أكثر تصريحية.

\n\n

كيف يعمل؟

\n\n

بدلاً من إرجاع null من دالة، أعد Optional. وبدلاً من التحقق، استخدم سلاسل الدوال.

\n\n
// سيء\npublic String getCity(User user) {\n    if (user == null) return "Unknown";\n    Address address = user.getAddress();\n    if (address == null) return "Unknown";\n    return address.getCity();\n}\n\n// جيد\npublic Optional<String> getCity(User user) {\n    return Optional.ofNullable(user)\n            .map(User::getAddress)\n            .map(Address::getCity);\n}\n\n// الاستخدام\nString city = getCity(someUser).orElse("Unknown");\n
\n\n

لاحظ: لا يوجد أي if. map يعمل فقط إذا كانت القيمة ليست null. إذا واجه null في أي مرحلة - تنقطع السلسلة وتحصل على Optional.empty().

\n\n

الطرق الشائعة لـ Optional

\n\n
    \n
  • orElse(T other) - إرجاع القيمة أو خيار احتياطي
  • \n
  • orElseGet(Supplier<? extends T> other) - نسخة كسولة، تُحسب فقط عند الحاجة
  • \n
  • orElseThrow(Supplier<? extends X> exceptionSupplier) - رمي استثناء مخصص
  • \n
  • ifPresent(Consumer<? super T> consumer) - تنفيذ إجراء إذا كانت القيمة موجودة
  • \n
  • filter(Predicate<? super T> predicate) - التصفية حسب شرط
  • \n
\n\n
// مثال مع الفلتر\nOptional<String> name = Optional.of("Java");\nname.filter(n -> n.startsWith("J"))\n    .ifPresent(System.out::println); // سيطبع "Java"\n
\n\n

هام: Optional مخصص للقيم المُعادة، وليس لحقول الفئة أو معاملات الدوال. لا تفرط في استخدامه.

\n\n

2. Objects.requireNonNull() - أداة للعقود الصريحة

\n\n

أحيانًا null هو خطأ ويجب اكتشافه في أقرب وقت ممكن. بدلاً من كتابة التحقق يدويًا، استخدم java.util.Objects.requireNonNull().

\n\n
public class UserService {\n    private final UserRepository repository;\n\n    public UserService(UserRepository repository) {\n        this.repository = Objects.requireNonNull(repository, \n            "UserRepository must not be null");\n    }\n\n    public User findById(Long id) {\n        Objects.requireNonNull(id, "ID must not be null");\n        return repository.findById(id);\n    }\n}\n
\n\n

هذا الأسلوب يسمى

المدونات

توصيات الكتب