为什么将null String强制转换为" null"串

时间:2014-07-05 22:56:33

标签: java

在阅读this question时,我想起了我在第一次学习java时编写的程序中的一个错误,这个错误让我永远定位并且基本上归结为以下行为:

String s1 = "This was a triumph";
String n1 = null;
System.out.println(s1 + n); // prints "This was a triumphnull"

类似行为的一些其他值得注意的例子(以及令人困惑的反例):

// "nullThis was a triumph", coercion happens commutatively
System.out.println(n1 + s1);

// as per above question, println explicitly converts null Strings to "null"
System.out.println(n1);

// similar result
System.out.println(String.valueOf(n1));

// NullPointerException (!!); null not silently converted to "null"
// note that this is the kind of thing I expected to occur for the other examples
// when I wrote the buggy code in the first place
System.out.println(n1.toString());

虽然我认为我在技术上理解这种行为,但我绝对不会了解它,所以我的问题是:

  1. 从语言设计的角度来看,为什么java将空字符串转换为" null"字符串在很多情况下?
  2. 为什么在它没有这样做的情况下这样做呢?
  3. 修改

    到目前为止,我很欣赏这些答案,但我只是想澄清一下,我的困惑很大程度上源于null Strings在这方面的处理方式与其他null对象的区别。例如:

    Integer i1 = 42;
    Integer n2 = null;
    // Both produce NullPointerExceptions:
    Integer.valueOf(n2);
    System.out.println(i1 + n2);
    

    我还想再强调NullPointerException是我期望的那种行为,这就是为什么我对null /" null"字符串转换首先。

2 个答案:

答案 0 :(得分:3)

只有对象有方法。 null不是一个对象;它没有方法。任何调用null方法的尝试都会引发NullPointerException。这有点类似于您尝试调用3.toString()时所获得的内容,尽管它是运行时错误而不是编译时。

您在null转换为"null"所有特殊情况空引用的过程中给出的示例,以尝试提供更友好的接口。他们可以这样做,因为它们不是null上的方法调用;他们可以进行内置x == null? "null" : x.toString()等额外处理。这类似于System.out.println(3)失败时可以调用3.toString()的原因。


null整数的处理通过自动装箱工作,这是一种与打印和字符串连接中处理null的机制完全无关的机制。

当一个Integer(或其他7个原始包装类型之一)出现在需要原始int的上下文中时,编译器会自动插入Integer.valueOf调用来执行转换。 Integer.valueOf没有空值的安全默认值;虽然"null"null的明显字符串形式,但对于调试输出非常有用,将空整数强制转换为0或任何其他值都不太有用,而且容易出错。< / p>

答案 1 :(得分:2)

1。这是一个设计选择,由String&amp; amp;从JDK1.0开始支持StringBuffer类(参见http://docs.oracle.com/javase/6/docs/api/java/lang/String.html等),这是自1996年1月21日以来 - 它支持使用+运算符连接从那时起。在J2SE 5.0(2004年9月30日),也称为JDK 1.5,StringBuilder(非线程安全,但速度更快 - +现在开始使用它而不是StringBuffer),自动装箱和泛型(带擦除)是补充 - 整个范式从使用反射的元编程转变为模板编程,而不是那么明显的铸造解决方案。 (参见例如https://codegolf.stackexchange.com/questions/28786/write-a-program-that-makes-2-2-5 - Java解决方案使用整数缓存中毒和装箱/拆箱来实现这个不太令人惊讶的结果)

String.java

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

Objects.java

public static String toString(Object o) {
    return String.valueOf(o);
}

PrintStream.java

public void println(Object x) {
    String s = String.valueOf(x);
    synchronized (this) {
        print(s);
        newLine();
    }
} 

StringBuilder.java

public StringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

等。 (Java src.zip,JDK v8)

几乎所有处理打印和toString转换的Java库方法都以这种方式处理null(即调用String.valueOf(),从而将其转换为文字“null”String)。另请注意,+的concat也可以这样工作,因为它在编译期间转换为库调用(调用StringBuilder.append(Object o))。

2。在空对象引用上显式调用#toString()仍然会导致NPEx,因为尝试调用其上的任何其他方法。

3。 (是的,我知道没有第3部分)有趣的时间,尝试执行,例如

System.out.println( ((String)null).toString() );

(显然失败了),然后

System.out.println( ((String)null).valueOf((String)null).toString() ); // works?! why!?

扰流器:

  

静态方法。