String.valueOf() vs. Object.toString()
In Java, is there any difference between String.valueOf(Object) and Object.toString()?
Yes. (And more so if you consider overloading!)
As the javadoc explains, String.valueOf((Object) null)
will be treated as a special case by the valueOf
method and the value "null"
is returned. By contrast, null.toString()
will just give you an NPE.
Overloading
It turns out that String.valueOf(null)
(note the difference!) does give an NPE ... despite the javadoc. The real explanation1 is obscure:
There are a number of overloads of
String.valueOf
, but there are two that are relevant here:String.valueOf(Object)
andString.valueOf(char[])
.In the expression
String.valueOf(null)
, both of those overloads are applicable, sincenull
is assignment compatible with any reference type.When there are two or more applicable overloads, the JLS says that the overload for the most specific argument type is chosen.
Since
char[]
is a subtype ofObject
, it is more specific.Therefore the
String.valueOf(char[])
overload is called.String.valueOf(char[])
throws an NPE if its argument is a null array. UnlikeString.valueOf(Object)
, it doesn't treatnull
as a special case.
Another example illustrates the difference in the valueOf(char[])
overload even more clearly:
char[] abc = new char[]('a', 'b', 'c');
System.out.println(String.valueOf(abc)); // prints "abc"
System.out.println(abc.toString()); // prints "[C@...."
Is there a specific code convention for these?
No.
Use which ever is most appropriate to the requirements of the context in which you are using it. (Do you need the formatting to work for null
?)
Note: that isn't a code convention. It is just common sense programming. It is more important that your code is correct than it is to follow some stylistic convention or "best practice" dogma2.
1 - You can confirm this by using javap -c
to examine the code of a method that has a String.valueOf(null)
call. Observe the overload that is used for the call.
2 - Please read "No Best Practices", and pass this reference on to the next person who tells you that it is "best practice" to do something in the programming or IT domains.
Personal opinion
Some developers acquire the (IMO) bad habit of "defending" against nulls. So you see lots of tests for nulls, and treating nulls as special cases. The idea seems to be prevent NPE from happening.
I think this is a bad idea. In particular, I think it is a bad idea if what you do when you find a null
is to try to "make good" ... without consideration of why there was a null
there.
In general, it is better to avoid the null
being there in the first place ... unless the null
has a very specific meaning in your application or API design. So, rather than avoiding the NPE with lots of defensive coding, it is better to let the NPE happen, and then track down and fix the source of the unexpected null
that triggered the NPE.
So how does this apply here?
Well, if you think about it, using String.valueOf(obj)
could be a way of "making good". That is to be avoided. If it is unexpected for obj
to be null
in the context, it is better to use obj.toString()
.
According to the Java documentation, String.valueOf()
returns:
if the argument is
null
, then a string equal to"null"
; otherwise, the value ofobj.toString()
is returned.
So there shouldn't really be a difference except for an additional method invocation.
Also, in the case of Object#toString
, if the instance is null
, a NullPointerException
will be thrown, so arguably, it's less safe.
public static void main(String args[]) {
String str = null;
System.out.println(String.valueOf(str)); // This will print a String equal to "null"
System.out.println(str.toString()); // This will throw a NullPointerException
}
Differences between String.valueOf(Object) and Object.toString() are:
1) If string is null,
String.valueOf(Object)
will return "null"
, whereas Object::toString()
will throw a null pointer exception.
public static void main(String args[]){
String str = null;
System.out.println(String.valueOf(str)); // it will print null
System.out.println(str.toString()); // it will throw NullPointerException
}
2) Signature:
valueOf() method of String class is static. whereas toString() method of String class is non static.
The signature or syntax of string's valueOf() method is given below:
public static String valueOf(boolean b)
public static String valueOf(char c)
public static String valueOf(char[] c)
public static String valueOf(int i)
public static String valueOf(long l)
public static String valueOf(float f)
public static String valueOf(double d)
public static String valueOf(Object o)
The signature or syntax of string's toString()
method is given below:
public String toString()
Most has already been mentioned by other answers, but I just add it for completeness:
- Primitives don't have a
.toString()
as they are not an implementation of theObject
-class, so onlyString.valueOf
can be used. String.valueOf
will transform a given object that isnull
to the String"null"
, whereas.toString()
will throw aNullPointerException
.The compiler will useEDIT: Actually, it will use theString.valueOf
by default when something likeString s = "" + (...);
is used. Which is whyObject t = null; String s = "" + t;
will result in the String"null"
, and not in a NPE.StringBuilder.append
, notString.valueOf
. So ignore what I said here.
In addition to those, here is actually a use case where String.valueOf
and .toString()
have different results:
Let's say we have a generic method like this:
public static <T> T test(){
String str = "test";
return (T) str;
}
And we'll call it with an Integer
type like this: Main.<Integer>test()
.
When we create a String with String.valueOf
it works fine:
String s1 = String.valueOf(Main.<Integer>test());
System.out.println(s1);
This will output test
to STDOUT.
With a .toString()
however, it won't work:
String s2 = (Main.<Integer>test()).toString();
System.out.println(s2);
This will result in the following error:
java.lang.ClassCastException
: classjava.lang.String
cannot be cast to classjava.lang.Integer
Try it online.
As for why, I can refer to this separated question and its answers. In short however:
- When using
.toString()
it will first compile and evaluate the object, where the cast toT
(which is anString
toInteger
cast in this case) will result in theClassCastException
. - When using
String.valueOf
it will see the genericT
asObject
during compilation and doesn't even care about it being anInteger
. So it will cast anObject
toObject
(which the compiler just ignores). Then it will useString.valueOf(Object)
, resulting in aString
as expected. So even though theString.valueOf(Object)
will do a.toString()
on the parameter internally, we've already skipped the cast and its treated like anObject
, so we've avoided theClassCastException
that occurs with the usage of.toString()
.
Just thought it was worth mentioning this additional difference between String.valueOf
and .toString()
here as well.