it-swarm.dev

لماذا يمكنني رمي فارغة في جافا؟

عند تشغيل هذا:

public class WhatTheShoot {

    public static void main(String args[]){
        try {
            throw null;
        } catch (Exception e){
            System.out.println(e instanceof NullPointerException);
            System.out.println(e instanceof FileNotFoundException);
        }
    }
}

الرد هو:

true  
false

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

لماذا يمكنني رمي فارغة في جافا ، ولماذا يبثها إلى NullPointerException؟

(في الواقع ، أنا لا أعرف ما إذا كان "منبثقًا" ، بالنظر إلى أنني ألقي باطلاً)}

بصرف النظر عن سؤال مقابلة غبي حقًا (من فضلك لا يسأل أحد هذا في مقابلة) ، لا يمكنني رؤية أي سبب لـ throw null. ربما تريد أن تطلق النار ، لكن هذا ... أعني ، لماذا يمكن لأي شخص throw null؟

حقيقة ممتعة IntelliJ IDEA 12 يخبرني أن خطي ، e instanceof NullPointerException ، سيكون دائمًا خاطئًا. هذا ليس صحيحا على الإطلاق.

306
bharal

يبدو أنه لا يتم التعامل مع null على أنه NullPointerException ، ولكن فعل محاولة throw null نفسه يلقي NullPointerException.

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

JLS 14.18 يحدد هذا السلوك:

إذا اكتملت عملية تقييم Expression بشكل طبيعي ، فنتجت قيمة فارغة ، ثم يتم إنشاء مثيل V من الفئة NullPointerException وإلقاؤه بدلاً من القيمة الخالية. اكتمال بيان الرمية فجأة ، والسبب هو رمي بقيمة V '.

408
Louis Wasserman

لماذا يبثها إلى NullPointerException؟

حسب JLS 14.18 :

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

لماذا يمكنني رمي فارغة في جافا؟

يمكنك رمي كائنات من النوع Throwable وبما أن null هو مرجع صالح لـ Throwable ، فإن برنامج التحويل البرمجي يسمح بذلك.

هذا هو ما يقول نيل غافتر

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

95
NINCOMPOOP

يتصرف وفقًا لـ JLS :

إذا اكتملت عملية تقييم Expression بشكل طبيعي ، فنتجت قيمة فارغة ، ثم يتم إنشاء مثيل V من الفئة NullPointerException وإلقاؤه بدلاً من القيمة الخالية.

21
assylias

التفكير في الأمر بهذه الطريقة يجعل الأمر أكثر وضوحًا بشأن سبب نجاح هذا الأمر:

try {
    Exception foo = null;
    if(false) {
        foo = new FileNotFoundException();
    } // Oops, forgot to set foo for the true case..
    throw foo;
} catch (Exception e){
    System.out.println(e instanceof NullPointerException);
    System.out.println(e instanceof FileNotFoundException);
}
18
Nick Gotch

لا أعرف بالتأكيد ، لكنني أظن أن "رمي لاغٍ" ؛ يعمل لا يعمل ، وتجربته يؤدي البرنامج إلى رمي استثناء ، ويحدث هذا الاستثناء ليكون (لفة الأسطوانة) NullPointerException ...

13
ajb