3

I just found something interesting.

public class test {

    public static void main(String a[])
    {
        System.out.println(String.valueOf(null).length());
    }

}

Output

Exception in thread "main" java.lang.NullPointerException
    at java.lang.String.<init>(Unknown Source)

This is what I kind of expected.

But when i run this

public class test {

    public static void main(String a[])
    {
        String s=null;
        System.out.println(String.valueOf(s).length());
    }

}

Output

4

There are two overloaded version of valueOf which gets called,they are

/**
     * Returns the string representation of the <code>Object</code> argument.
     *
     * @param   obj   an <code>Object</code>.
     * @return  if the argument is <code>null</code>, then a string equal to
     *          <code>"null"</code>; otherwise, the value of
     *          <code>obj.toString()</code> is returned.
     * @see     java.lang.Object#toString()
     */
    public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
    }

    /**
     * Returns the string representation of the <code>char</code> array
     * argument. The contents of the character array are copied; subsequent
     * modification of the character array does not affect the newly
     * created string.
     *
     * @param   data   a <code>char</code> array.
     * @return  a newly allocated string representing the same sequence of
     *          characters contained in the character array argument.
     */
    public static String valueOf(char data[]) {
    return new String(data);
    }

I didn't get why valueOf(Object s) method is giving special treatment to null. Thoughts/Comments?

RockAndRoll
  • 2,247
  • 2
  • 16
  • 35
  • Because the best suitable method is being found and its being processed. Even though you are setting the String s to null, you have declared a String which is occupying memory. That is why you are getting output as 4.# – We are Borg Sep 24 '15 at 12:39
  • 4
    I think the real question here is not why the output is 4 or a NPE is thrown but why both method act differently given null as parameter. – Tunaki Sep 24 '15 at 12:44
  • I kind of agree with Tunaki why this difference when given null as parameter. – RockAndRoll Sep 24 '15 at 12:48
  • 1
    _"I didn't get why valueOf(Object s) method is giving special treatment to null. "_ For `valueOf(Object obj)`, the check is there to avoid you calling a method on a potential `null` reference. If it wasn't there, this method would be completely pointless as it's the same as calling `myObj.toString()`. So it's a utility method (o/w everyone would have it in its code base I guess). – Alexis C. Sep 24 '15 at 12:54

2 Answers2

3

The problem is from the method invocation logic of JLS.

JLS's Choosing the Most Specific Method states,

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

Now, in your first case, when you pass null directly,

System.out.println(String.valueOf(null).length());

Both String.valueOf(Object) and String.valueOf(char[]) are applicable... So it uses the most specific method which is a char[].

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.

But in your second case, you are actually passing a String even though it's null.

So only String.valueOf(Object) is applicable.

Codebender
  • 14,221
  • 7
  • 48
  • 85
  • We can help compiler chose *safe* method by explicitly showing which overloaded version we are interested in. We can do it by casting `null` to specific type like `String.valueOf((String)null)` which will invoke `valueOf(Object)`. – Pshemo Sep 24 '15 at 13:24
2

From valueOf docs

if the argument is null, then a string equal to "null"; otherwise, the value of obj.toString() is returned.

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307