Почему String.valueOf (null) генерирует исключение NullPointerException? - PullRequest
116 голосов
/ 28 июня 2010

согласно документации, метод String.valueOf(Object obj) возвращает:

, если аргумент равен null, тогда строка равна "null";в противном случае возвращается значение obj.toString().

Но почему я пытаюсь сделать следующее:

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

вместо этого выдается NPE?(попробуйте сами, если не верите!)

    Exception in thread "main" java.lang.NullPointerException
    at java.lang.String.(Unknown Source)
    at java.lang.String.valueOf(Unknown Source)

Как это случилось?Лежит ли документация?Это серьезная ошибка в Java?

Ответы [ 3 ]

191 голосов
/ 28 июня 2010

Проблема в том, что String.valueOf метод перегружен :

Язык спецификаций Java предписывает, что в таких случаях выбирается наиболее специфичная перегрузка :

JLS 15.12.2.5 ВыборНаиболее специфический метод

Если более одного метода-члена доступны и применимы для вызова метода, необходимо выбрать один, чтобы предоставить дескриптор для отправки метода во время выполнения.Язык программирования Java использует правило, согласно которому выбирается самый специфический метод.

A char[] is-an Object, но не всеObject is-a char[].Следовательно, char[] является более конкретным , чем Object, и, как указано языком Java, в этом случае выбирается перегрузка String.valueOf(char[]).

String.valueOf(char[]) ожидает массивчтобы быть не-null, и, поскольку в этом случае дается null, он выдает NullPointerException.

. Простое "исправление" заключается в явном приведении null к Object какследует:

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

Смежные вопросы


Мораль истории

Есть несколько важных:

  • Эффективная Java 2ndРедакция, пункт 41: Используйте разумную перегрузку
    • То, что вы можете перегружать, не означает, что вы должны это делать каждый раз
    • Они могут вызывать путаницу (особенно если методы делают совершенно разные вещи)
  • Используя хорошую IDE, вы можете проверить, какая перегрузка выбрана во время компиляции
    • С Eclipse вы можете навести указатель мыши на указанное выше выражение и увидеть, что действительно , перегрузка valueOf(char[]) выбрана!
  • Иногда вы хотите явноприведение null (примеры для подражания)

См. также


При приведении null

Существуют как минимум две ситуации, когда необходимо явное приведение null к определенному ссылочному типу:

  • Чтобы выбрать перегрузку (как указано в примере выше)
  • Чтобы дать null в качестве одного аргумента для параметра vararg

ПростойПример последнего:

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

Тогда мы можем иметь следующее:

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

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

См. также

Смежные вопросы

16 голосов
/ 28 июня 2010

Проблема в том, что вы звоните String.valueOf(char[]) и , а не String.valueOf(Object).

Причина в том, чтоJava всегда будет выбирать наиболее конкретную версию перегруженного метода, который работает с предоставленными параметрами.null является допустимым значением для параметра Object, но также является допустимым значением для параметра char[].

Чтобы заставить Java использовать версию Object, либо передайте null черезпеременная или указать явное приведение к объекту:

Object o = null;
System.out.println("String.valueOf(null) = " + String.valueOf(o));
// or
System.out.println("String.valueOf(null) = " + String.valueOf((Object) null));
5 голосов
/ 01 ноября 2012

Ошибка, пронумерованная 4867608 , была подана для этого способа еще в 2003 году, которая была решена как "не исправит" с этим объяснением.

Мы не можем изменить это из-за ограничений совместимости. Обратите внимание, что это открытый статический метод String valueOf (char data []), который заканчивается вызывается, и он не упоминает замену «ноль» для нулевые аргументы.

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

...