Boolean.valueOf () bazen NullPointerException üretir


115

Bu koda sahibim:

package tests;

import java.util.Hashtable;

public class Tests {

    public static void main(String[] args) {

        Hashtable<String, Boolean> modifiedItems = new Hashtable<String, Boolean>();

        System.out.println("TEST 1");
        System.out.println(modifiedItems.get("item1")); // Prints null
        System.out.println("TEST 2");
        System.out.println(modifiedItems.get("item1") == null); // Prints true
        System.out.println("TEST 3");
        System.out.println(Boolean.valueOf(null)); // Prints false
        System.out.println("TEST 4");
        System.out.println(Boolean.valueOf(modifiedItems.get("item1"))); // Produces NullPointerException
        System.out.println("FINISHED!"); // Never executed
    }
}

Benim sorunum, Test 3'ün neden iyi çalıştığını (yazdırıyor falseve üretmiyor NullPointerException) bu arada Test 4'ün bir NullPointerException. Eğer testlerde görebileceğiniz gibi 1 ve 2 , nullve modifiedItems.get("item1")eşittir ve vardır null.

Davranış, Java 7 ve 8'de aynıdır.


modifiyeItems.get ("item1") bu null, bunun farkındasınız, ancak bunu bir valueOf'ye geçirmenin bir NPE ile sonuçlanmayacağını varsayıyorsunuz?
Stultuske

16
@Stultuske: Bu gerçek bir geçirmeden yukarıda sadece iki satır göz önüne alındığında geçerli bir soru, var nullaynı işleve değil bir NPE üretmek! Bunun iyi bir nedeni var, ancak ilk bakışta kesinlikle kafa karıştırıcı :-)
psmears

25
Etkilendim. Bu, yıllardır gördüğüm en ilginç boş işaretçi istisna sorusudur.
candied_orange

@Jeroen bu, bu sorunun bir kopyası değil . Kutudan çıkarmanın iki problemde ortak olduğu doğru olsa da, burada hiçbir karşılaştırma yapılmamaktadır. Bu sorunun en önemli yanı, aşırı yüklerin çözülme şekli nedeniyle ortaya çıkmasıdır; ve bu, nasıl ==uygulandığından oldukça farklı bir şey .
Andy Turner

Yanıtlar:


178

Hangi aşırı yüklemenin başlatıldığına dikkatlice bakmalısınız:

  • Boolean.valueOf(null)çağırıyor Boolean.valueOf(String). Bu, NPEboş bir parametre ile sağlansa bile bir bile atmaz .
  • Boolean.valueOf(modifiedItems.get("item1"))çağrılıyor Boolean.valueOf(boolean), çünkü modifiedItems's değerleri, Booleankutudan çıkarma dönüşümü gerektiren türde . Yana modifiedItems.get("item1")olduğunu null, bu değerin kutudan çıkarma - değil Boolean.valueOf(...)- NPE atar hangi.

Hangi aşırı yüklemenin başlatıldığını belirleme kuralları oldukça belirsizdir , ancak kabaca şu şekildedir :

  • İlk geçişte, kutulama / kutudan çıkarma işlemine (veya değişken arity yöntemlerine) izin verilmeden bir yöntem eşleşmesi aranır.

    • Çünkü nulla için kabul edilebilir bir değerdir Stringama değil boolean, bu geçişte Boolean.valueOf(null)eşleştirilir Boolean.valueOf(String);
    • BooleanBoolean.valueOf(String)veya için kabul edilebilir değildir Boolean.valueOf(boolean), bu nedenle bu geçişte hiçbir yöntem eşleştirilmez Boolean.valueOf(modifiedItems.get("item1")).
  • İkinci bir geçişte, kutulama / kutudan çıkarma işlemine izin veren bir yöntem eşleşmesi aranır (ancak yine de değişken arity yöntemleri değildir).

    • A Booleankutudan çıkarılabilir boolean, dolayısıyla bu geçişte Boolean.valueOf(boolean)eşleştirilir Boolean.valueOf(modifiedItems.get("item1")); ancak onu çağırmak için derleyici tarafından kutudan çıkarma dönüşümünün eklenmesi gerekir:Boolean.valueOf(modifiedItems.get("item1").booleanValue())
  • (Değişken arity yöntemlerine izin veren üçüncü bir geçiş vardır, ancak ilk iki geçiş bu durumlarla eşleştiği için burada geçerli değildir)


3
Boolean.valueOf(modifiedItems.get("item1").booleanValue())Bunun yerine kaynak kodda kullanırsak kod daha net olabilir Boolean.valueOf(modifiedItems.get("item1"))mi?
CausingUnderflowsEverywhere

1
@CausingUnderflowsHer yerde gerçekten değil - .booleanValue()ifadede gömülü olduğunu görmek gerçekten zor . İki gözlem: 1) otomatik (un) kutulama, sözdizimsel kusurları ortadan kaldırmak için Java'nın kasıtlı bir özelliğidir; bunu kendin yapmak mümkündür ama deyimsel değil; 2) bu size hiç yardımcı olmaz - kesinlikle sorunun oluşmasını durdurmaz ve hata oluştuğunda fazladan bilgi vermez (yığın izleme aynı olacaktır, çünkü çalıştırılan kod aynıdır).
Andy Turner

@CausingUnderflows Her yerde sorunları vurgulamak için araç kullanmak daha iyidir, örneğin, intellij burada potansiyel NPE hakkında size kazanç sağlar.
Andy Turner

13

Yana modifiedItems.getdöndüren Boolean(olup olmayan bir şekilde dökümü yapılabilen, String) 'dir kullanılacak imza Boolean.valueOf(boolean), Booleanbir nesnenin üstüne outboxed edilir boolean. Oraya nullgeri dönüldüğünde, giden kutusu bir NullPointerException.


11

Yöntem imzası

Yöntemin Boolean.valueOf(...)iki imzası vardır:

  1. public static Boolean valueOf(boolean b)
  2. public static Boolean valueOf(String s)

Senin modifiedItemsdeğerin Boolean. Sen döküm olamaz Booleaniçin Stringyani sonuç ilk imza seçilecektir

Boole kutudan çıkarma

İfadende

Boolean.valueOf(modifiedItems.get("item1"))

hangisi olarak okunabilir

Boolean.valueOf(modifiedItems.get("item1").booleanValue())   

Ancak, temelde sahip olacağınız için modifiedItems.get("item1")dönernull

null.booleanValue()

ki bu açıkça bir NullPointerException


Yanlış ifade, işaret ettiğiniz için teşekkürler ve cevap, geri bildiriminizin ardından güncellenir. Özür dilerim, yazarken cevabınızı görmedim ve benimki size benziyor. OP için karışıklığı önlemek için cevabımı kaldırmalı mıyım?
Al-un

4
Benim hesabımdan silmeyin. Unutmayın, bu sıfır toplamlı bir oyun değildir: insanlar birden fazla yanıta oy verebilir (ve yapabilir).
Andy Turner

3

Andy'nin zaten çok iyi tarif ettiği gibi NullPointerException:

Boolean'ın kutudan çıkarılmasından kaynaklanmaktadır:

Boolean.valueOf(modifiedItems.get("item1"))

dönüştürülmek:

Boolean.valueOf(modifiedItems.get("item1").booleanValue())

çalışma zamanında ve sonra null NullPointerExceptionise atar modifiedItems.get("item1").

Şimdi buraya bir noktayı daha eklemek istiyorum, aşağıdaki sınıfların ilgili ilkellerine kutudan çıkarılması, NullPointerExceptionkarşılık gelen döndürülen nesneler boş ise istisna üretebilir .

  1. bayt - Bayt
  2. char - Karakter
  3. float - Float
  4. int - Tamsayı
  5. uzunca
  6. kısa - Kısa
  7. çift ​​- Çift

İşte kod:

    Hashtable<String, Boolean> modifiedItems1 = new Hashtable<String, Boolean>();
    System.out.println(Boolean.valueOf(modifiedItems1.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Byte> modifiedItems2 = new Hashtable<String, Byte>();
    System.out.println(Byte.valueOf(modifiedItems2.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Character> modifiedItems3 = new Hashtable<String, Character>();
    System.out.println(Character.valueOf(modifiedItems3.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Float> modifiedItems4 = new Hashtable<String, Float>();
    System.out.println(Float.valueOf(modifiedItems4.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Integer> modifiedItems5 = new Hashtable<String, Integer>();
    System.out.println(Integer.valueOf(modifiedItems5.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Long> modifiedItems6 = new Hashtable<String, Long>();
    System.out.println(Long.valueOf(modifiedItems6.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Short> modifiedItems7 = new Hashtable<String, Short>();
    System.out.println(Short.valueOf(modifiedItems7.get("item1")));//Exception in thread "main" java.lang.NullPointerException

    Hashtable<String, Double> modifiedItems8 = new Hashtable<String, Double>();
    System.out.println(Double.valueOf(modifiedItems8.get("item1")));//Exception in thread "main" java.lang.NullPointerException

1
"Çalışma zamanında ... biçimine dönüştürülür", derleme zamanında buna dönüştürülür.
Andy Turner

0

Bunu anlamanın bir yolu, ne zaman Boolean.valueOf(null)çağrıldığıdır, java'ya tam olarak boş değeri vermesi söylenir.

Ancak, Boolean.valueOf(modifiedItems.get("item1"))çağrıldığında, java'ya Boolean nesne türünün HashTable'ından bir değer alması söylenir, ancak Boolean'ı beklemesine rağmen bunun yerine bir çıkmaz (boş) bulduğu Boolean türünü bulamaz. NullPointerException istisnası, java'nın bu bölümünün yaratıcıları, bu durumun programda programcının dikkatini gerektiren bir ters giden bir durum olduğuna karar verdikleri için atıldı. (İstenmeyen bir şey oldu.)

Bu durumda, kasıtlı olarak boş değerin orada olmasını amaçladığınızı bildirmek ile java'nın bir nesnenin bulunmasının amaçlandığı bir nesneye (boş) eksik bir referans bulması arasındaki fark daha fazladır.

Bu yanıtta NullPointerException hakkında daha fazla bilgi görün: https://stackoverflow.com/a/25721181/4425643


Birisi bu cevabı iyileştirmeye yardımcı olabilirse, programcının net bir niyetle, belirsizlik olmadan bir şeyler yazmasına gönderme yapan bir kelime düşünüyordum
CausingUnderflowsEverywhere
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.