Dlaczego String.valueOf (null) zgłasza wyjątek NullPointerException?

130

zgodnie z dokumentacją metoda String.valueOf(Object obj)zwraca:

jeśli argumentem jest null, to łańcuch równy "null"; w przeciwnym razie zwracana obj.toString()jest wartość .

Ale jak to się dzieje, kiedy próbuję to zrobić:

System.out.println("String.valueOf(null) = " + String.valueOf(null));

zamiast tego rzuca NPE? (spróbuj sam, jeśli nie wierzysz!)

    Wyjątek w wątku „main” java.lang.NullPointerException
    w java.lang.String. (nieznane źródło)
    w java.lang.String.valueOf (nieznane źródło)

Jak to się dzieje? Czy dokumentacja mnie okłamuje? Czy to poważny błąd w Javie?

user282886
źródło

Odpowiedzi:

205

Problem polega na tym, że String.valueOfmetoda jest przeciążona :

Java Specification Language wymaga, aby w tego rodzaju przypadkach wybierać najbardziej szczegółowe przeciążenie :

JLS 15.12.2.5 Wybór najbardziej szczegółowej metody

Jeśli więcej niż jedna metoda składowa jest zarówno dostępna, jak i odpowiednia do wywołania metody, konieczne jest wybranie jednej, która zapewni deskryptor do wysyłania metody w czasie wykonywania. W języku programowania Java obowiązuje zasada, że wybierana jest najbardziej szczegółowa metoda.

A char[] jest-an Object , ale nie wszystko Object jest-a char[] . W związku z tym char[]jest bardziej szczegółowe niż Objecti zgodnie z opisem w języku Java String.valueOf(char[])w tym przypadku wybierane jest przeciążenie.

String.valueOf(char[])oczekuje, że tablica nie będzie null, a ponieważ nulljest podana w tym przypadku, zgłasza NullPointerException.

Łatwym "rozwiązaniem" jest nulljawne rzutowanie w Objectnastępujący sposób:

System.out.println(String.valueOf((Object) null));
// prints "null"

Powiązane pytania


Morał historii

Jest kilka ważnych:

  • Efektywna Java 2nd Edition, pozycja 41: rozsądnie używaj przeciążania
    • To, że możesz przeciążać, nie oznacza, że ​​powinieneś za każdym razem
    • Mogą powodować zamieszanie (zwłaszcza jeśli metody dają bardzo różne efekty)
  • Korzystając z dobrego IDE, możesz sprawdzić, które przeciążenie jest wybrane w czasie kompilacji
    • Z Eclipse, można myszką widzimy po powyższej wypowiedzi i widzę, że rzeczywiście The valueOf(char[])wybrano przeciążenie!
  • Czasami chcesz jawnie przesyłać null(przykłady do naśladowania)

Zobacz też


Na castingu null

Istnieją co najmniej dwie sytuacje, w których jawne rzutowanie nullna określony typ odniesienia jest konieczne:

  • Aby wybrać przeciążenie (jak podano w powyższym przykładzie)
  • Aby dać nulljako pojedynczy argument do parametru vararg

Prosty przykład tego ostatniego jest następujący:

static void vararg(Object... os) {
    System.out.println(os.length);
}

Następnie możemy mieć:

vararg(null, null, null); // prints "3"
vararg(null, null);       // prints "2"
vararg(null);             // throws NullPointerException!

vararg((Object) null);    // prints "1"

Zobacz też

Powiązane pytania

smary wielogenowe
źródło
5
Inna sugestia: kiedy przeciążasz metodę i jeden argument może zostać wywołany na dwóch przeciążeniach (tak jak nullw tym przypadku), upewnij się, że oba przeciążenia działają tak samo w odniesieniu do tej wartości!
Joachim Sauer
3
@Joachim: Właśnie przeczytałem ten artykuł i byłem mile zaskoczony, gdy odkryłem, że te dwie metody zostały wyraźnie omówione! Bloch poszedł o krok dalej i stwierdził, że od tego czasu String.valueOf(Object)i tak valueOf(char[])robi zupełnie inne rzeczy (niezależnie od tego, nullczy nie), że być może w ogóle nie powinni byli być przeciążeni.
polygenelubricants
Masz pytanie ... jeśli masz metodę, która zwraca Object, to instrukcja return null;byłaby dokładnie taka sama jak return (Object) null;?
user972276
17

Problem w tym, że dzwonisz, String.valueOf(char[])a nie String.valueOf(Object) .

Powodem tego jest fakt, że Java zawsze wybiera najbardziej konkretną wersję przeciążonej metody, która działa z podanymi parametrami. nulljest prawidłową wartością Objectparametru, ale jest również prawidłową wartością char[]parametru.

Aby Java używała tej Objectwersji, przekaż ją nullprzez zmienną lub określ jawne rzutowanie na Object:

Object o = null;
System.out.println("String.valueOf(null) = " + String.valueOf(o));
// or
System.out.println("String.valueOf(null) = " + String.valueOf((Object) null));
Joachim Sauer
źródło
5

Błąd o numerze 4867608 został zgłoszony w ten sposób w 2003 r., Który został rozwiązany jako „nie da się naprawić” za pomocą tego wyjaśnienia.

Nie możemy tego zmienić z powodu ograniczeń zgodności. Zauważ, że jest to publiczna statyczna metoda String valueOf (char data []), która zostaje wywołana i nie wspomina o zamianie „null” na puste argumenty.

@ ###. ### 2003-05-23

cbare
źródło
0

Użyj String.valueOf(null: Any)w Scali.

Profiterole
źródło