欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 宝鼎售后问题提交 | 后台管理


新闻资讯

MENU

软件开发知识

Java String 对 null 昆山软件定制开发 工具的容错处理惩罚

点击: 次  来源:劳务派遣管理系统 时间:2017-12-20

原文出处: 肖汉松

媒介

最近在读《Thinking in Java》,看到这样一段话:

Primitives that are fields in a class are automatically initialized to zero, as noted in the Everything Is an Object chapter. But the object references are initialized to null, and if you try to call methods for any of them, you’ll get an exception-a runtime error. Conveniently, you can still print a null reference without throwing an exception.

大意是:原生范例会被自动初始化为 0,劳务派遣管理系统,可是工具引用会被初始化为 null,假如你实验挪用该工具的要领,就会抛出空指针异常。凡是,你可以打印一个 null 工具而不会抛出异常。

第一句相信各人城市容易领略,这是范例初始化的基本常识,可是第二句就让我很迷惑:为什么打印一个 null 工具不会抛出异常?带着这个疑问,我开始相识惑之旅。下面我将具体叙述我办理这个问题的思路,而且深入 JDK 源码找到问题的谜底。

办理问题的进程

可以发明,其实这个问题有几种环境,所以我们分类接头各类环境,昆山软件开发,看最后能不能获得谜底。

首先,我们把这个问题解析为三个小问题,逐一办理。

第一个问题

直接打印 null 的 String 工具,会获得什么功效?

String s = null;
System.out.print(s);

运行的功效是

null

公然如书上说的没有抛出异常,而是打印了null。显然问题的线索在于print函数的源码中。我们找到print的源码:

public void print(String s) {
    if (s == null) {
        s = "null";
    }
    write(s);
}

看到源码才发明本来就只是加了一句判定罢了,简朴粗暴,大概你对 JDK 的简朴实现有点失望了。安心,第一个问题只是开胃菜罢了,大餐还在后头。

第二个问题

打印一个 null 的非 String 工具,譬喻说 Integer:

Integer i = null;
System.out.print(i);

运行的功效不出料想:

null

我们再去看看print的源码:

public void print(Object obj) {
    write(String.valueOf(obj));
}

有点纷歧样的了,看来奥秘藏在valueOf内里。

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

看到这里,我们终于发明白打印 null 工具不会抛出异常的奥秘。print要领对 String 工具和非 String 工具分隔举办处理惩罚。

  1. String 工具:直接判定是否为 null,昆山软件开发,假如为 null 给 null 工具赋值为”null”。
  2. 非 String 工具:通过挪用String.valueOf要领,假如是 null 工具,就返回”null”,不然挪用工具的toString要领。

通过上面的处理惩罚,可以担保打印 null 工具不会堕落。

到这里,本文就应该竣事了。
什么?说好的大餐呢?上面还不足塞牙缝呢。
恶作剧啦。下面我们来探讨第三个问题。

第三个问题(埋没的大餐)

null 工具与字符串拼接会获得什么功效?

String s = null;
s = s + "!";
System.out.print(s);

功效大概你也猜到了:

null!

为什么呢?跟踪代码运行可以发明,这回跟print没有什么干系。可是上面的代码就挪用了print函数,不是它会是谁呢?+的嫌疑最大,可是+又不是函数,我们怎么看到它的源代码?这种环境,独一的表明就是编译器动了手脚,天网恢恢,疏而不漏,找不到源代码,我们可以去看看编译器生成的字节码。

L0
 LINENUMBER 27 L0
 ACONST_NULL
 ASTORE 1
L1
 LINENUMBER 28 L1
 NEW java/lang/StringBuilder
 DUP
 INVOKESPECIAL java/lang/StringBuilder.<init> ()V
 ALOAD 1
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 LDC "!"
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
 ASTORE 1
L2
 LINENUMBER 29 L2
 GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
 ALOAD 1
 INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/String;)V

看了上面的字节码是不是一头雾水?这里我们就要扯开话题,来侃侃+字符串拼接的道理了。

编译器对字符串相加会举办优化,首先实例化一个StringBuilder,然后把相加的字符串按顺序append,最后挪用toString返回一个String工具。不信你们看看上面的字节码是不是呈现了StringBuilder。具体的表明参考这篇文章 Java细节:字符串的拼接。

String s = "a" + "b";
//等价于
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
String s = sb.toString();