لا أحد يحب NullPointerException! هل هناك أي طريقة لتجنبهم؟ ربما. .
ستناقش هذه المقالة التقنيات التالية
1. النوع الاختياري (الذي تم تقديمه حديثًا في Java 8)
2. فئة الكائنات (الأصلية في Java 7)
فئة اختيارية في Java 8
ما هذا؟
1. الأنواع الجديدة المقدمة في Java 8
2. يتم استخدامه كغلاف لكائن من نوع محدد أو للسيناريوهات التي لا يوجد فيها كائن (خالي)
ببساطة، إنه بديل أفضل للتعامل مع القيم الخالية (تحذير: قد لا يكون الأمر واضحًا للوهلة الأولى)
الاستخدام الأساسي
إنه نوع (فئة) - فكيف يمكنك إنشاء مثيل من هذا النوع؟
ما عليك سوى استخدام طرقه الثابتة الثلاث:
انسخ رمز الكود كما يلي:
عام ثابت اختياري<String> stringOptional(String input) {
إرجاع اختياري.of(input);
}
بسيط وواضح - قم بإنشاء غلاف اختياري يحتوي على هذه القيمة. تذكر - إذا كانت هذه القيمة فارغة، فسيتم طرح NPE!
انسخ رمز الكود كما يلي:
عام ثابت اختياري<String> stringNullableOptional(String input) {
إذا (!new Random().nextBoolean()) {
الإدخال = فارغ؛
}
إرجاع اختياري.ofNullable(input);
}
أنا شخصيا أعتقد أنه أفضل. بهذه الطريقة لن يكون هناك خطر NPE - إذا كان الإدخال فارغًا، فسيتم إرجاع اختياري فارغ.
انسخ رمز الكود كما يلي:
عام ثابت اختياري<سلسلة> فارغاختياري() {
إرجاع اختياري. فارغ () ؛
}
إذا كنت تريد حقًا إرجاع قيمة "خالية". القيمة "الفارغة" لا تعني أنها خالية.
حسنًا، فكيف تستهلك/تستخدم اختياريًا؟
انسخ رمز الكود كما يلي:
استهلاك الفراغ العام الثابتاختياري () {
اختياري<String> ملفوف = اختياري.of("aString");
إذا (wrapped.isPresent()) {
System.out.println("حصلت على سلسلة -" + ملفوفة.get());
}
آخر {
System.out.println("مسكتك!");
}
}
الطريقة البسيطة هي التحقق مما إذا كان الغلاف الاختياري له قيمة بالفعل (باستخدام طريقة isPresent) - سوف تتساءل عن الميزة التي يتمتع بها هذا على استخدام if(myObj != null). لا تقلق، سأشرح ذلك بوضوح.
انسخ رمز الكود كما يلي:
الفراغ العام الثابت يستهلكNullableOptional() {
إدخال السلسلة = فارغ؛
إذا (جديد عشوائي ().nextBoolean ()) {
input = "iCanBeNull";
}
اختياري<String> ملفوف = اختياري.ofNullable(input);
System.out.println(wrapped.orElse("default"));
}
يمكنك استخدام طريقة orElse، بحيث إذا كانت القيمة المغلفة هي بالفعل قيمة فارغة، فيمكنك استخدامها لإرجاع قيمة افتراضية - ففوائدها واضحة. عند استخراج القيمة الحقيقية، يمكنك تجنب الطريقة المتكررة بشكل واضح لاستدعاء طريقة ifPresent.
انسخ رمز الكود كما يلي:
الفراغ العام الثابت يستهلكEmptyOptional() {
إدخال السلسلة = فارغ؛
إذا (جديد عشوائي ().nextBoolean ()) {
input = "iCanBeNull";
}
اختياري<String> ملفوف = اختياري.ofNullable(input);
System.out.println(wrapped.orElseGet(
() -> {
إرجاع "defaultBySupplier";
}
));
}
أنا مرتبك قليلاً بشأن هذا. لماذا هناك طريقتان مختلفتان لنفس الغرض؟ من الواضح أنه يمكن تحميل orElse وorElseGet بشكل زائد (بالاسم نفسه ولكن بمعلمات مختلفة).
على أي حال، الفرق الواضح بين هاتين الطريقتين هو المعلمات الخاصة بهما - يمكنك اختيار استخدام تعبيرات lambda بدلاً من مثيلات المورد لإنجاز ذلك (واجهة وظيفية)
لماذا يعد استخدام الاختياري أفضل من التحقق من القيمة الفارغة الشائعة؟
1. أكبر ميزة لاستخدام الاختياري هي أنه يمكنك التعبير عن نيتك بشكل أكثر وضوحًا - فإرجاع قيمة فارغة سيجعل المستهلكين في حيرة من أمرهم (عندما يحدث NPE) ما إذا كان قد تم إرجاعها عن قصد، لذلك عليك التحقق من موضع javadoc لمزيد من التفاصيل . يعد استخدام الاختياري أمرًا بسيطًا للغاية.
2. باستخدام الخيار الاختياري، يمكنك تجنب NPE تمامًا - كما ذكرنا أعلاه، فإن استخدام اختياري.ofNullable، وorElse، وorElseGet يمكن أن يبعدنا عن NPE.
منقذ آخر!
ألقِ نظرة على مقتطف الرمز هذا وانسخ الرمز أدناه:
الحزمة com.abhirockzz.wordpress.npesaviors؛
import java.util.Map;
استيراد java.util.Objects؛
الطبقة العامة باستخدام الكائنات {
String getVal(Map<String, String> aMap, String key) {
إرجاع aMap.containsKey(key) ؟ aMap.get(key) : فارغ;
}
public static void main(String[] args) {
UsingObjects obj = newUsingObjects();
obj.getVal(null, "dummy");
}
}
أي واحد قد يكون فارغا؟
1. كائن الخريطة
2. المفتاح المستخدم للبحث
3. هذا المثيل لاستدعاء الأسلوب
إذا تم طرح NPE، فكيف يمكننا تحديد أي منها فارغ؟
انسخ رمز الكود كما يلي:
الحزمة com.abhirockzz.wordpress.npesaviors؛
import java.util.Map;
استيراد java.util.Objects؛
الطبقة العامة باستخدام الكائنات {
String getValSafe(Map<String, String> aMap, String key) {
Map<String, String>safeMap = Objects.requireNonNull(aMap,
"الخريطة فارغة");
String SafeKey = Objects.requireNonNull(key, "Key is null");
إرجاع SafeMap.containsKey(safeKey) ؟safeMap.get(safeKey) : null;
}
public static void main(String[] args) {
UsingObjects obj = newUsingObjects();
obj.getValSafe(null, "dummy");
}
}
طريقة requireNonNull
1. إذا لم يكن الكائن فارغًا، قم بإرجاع نفسه
2. إذا كانت القيمة فارغة، فستحتوي NPE التي تم إرجاعها على الرسالة المحددة.
لماذا هو أفضل من if(myObj!=null)؟
سيرى تتبع المكدس الذي تراه بوضوح استدعاء الأسلوب Objects.requireNonNull. وهذا، بالإضافة إلى سجل الأخطاء الخاص بك، يمكن أن يسمح لك بتحديد المشكلة بشكل أسرع. . . على الأقل هو أسرع في رأيي.
يمكنك أيضًا تخصيص أداة التحقق الخاصة بك، مثل تنفيذ أداة التحقق البسيطة للتأكد من عدم وجود قيم فارغة.
انسخ رمز الكود كما يلي:
import java.util.Collections;
import java.util.List;
استيراد java.util.Objects؛
import java.util.function.Predicate;
الطبقة العامة RandomGist {
عامة ثابتة <T> T requireNonEmpty(T object, Predicate<T> predicate, String msgToCaller){
Objects.requireNonNull(object);
Objects.requireNonNull(predicate);
إذا (المسند. اختبار (كائن)) {
رمي IllegalArgumentException(msgToCaller) الجديد ؛
}
كائن العودة؛
}
public static void main(String[] args) {
// الاستخدام 1: سلسلة فارغة (مقصودة)
سلسلة س = ""؛
System.out.println(requireNonEmpty(Objects.requireNonNull(s), (s1) -> s1.isEmpty() , "سلسلتي فارغة!"));
// الاستخدام 2: قائمة فارغة (مقصودة)
قائمة القائمة = Collections.emptyList();
System.out.println(requireNonEmpty(Objects.requireNonNull(list), (l) -> l.isEmpty(), "القائمة فارغة!").size());
// الاستخدام 3: مستخدم فارغ (مقصود)
مستخدم المستخدم = مستخدم جديد("");
System.out.println(requireNonEmpty(Objects.requireNonNull(user), (u) -> u.getName().isEmpty(), "المستخدم فارغ!"));
}
مستخدم فئة ثابتة خاصة {
اسم سلسلة خاصة؛
المستخدم العام (اسم السلسلة) {
this.name = name;
}
سلسلة عامة getName () {
اسم الإرجاع؛
}
}
}
لا تدع NPE يصبح مؤلمًا في المكان الخطأ. لدينا العديد من الأدوات للتعامل بشكل أفضل مع NPEs وحتى القضاء عليها تمامًا!