判斷對象是否爲null,小夥竟然用StringUtils.isEmpty(obj+"")

我在代碼走查時,發現下面的代碼。其中Line133行的StringUtils.isEmpty(levyId+"")引起了我的注意。levyId是Long,你這樣判斷Long是否爲null,靠譜嗎?

 

 

答案是:不靠譜!

當levyId是null時,levyId+""的值是什麼? 是字符串null喲~~ 顯然,StringUtils.isEmpty("null") 是false。所以,還是老老實實地用 levyId==null來判斷Long是否爲null吧。

 

那麼,爲什麼levyId+""在levyId是null時的值是字符串null?

 

在Java中,當你對一個對象使用加號 "+" 進行字符串連接時,實際上是先調用了String#valueOf方法將對象轉換爲字符串。

走,帶你去司空見慣的java.lang.String小星球,看看它的靜態成員valueOf方法。可以看到,valueOf有許多重載,除了valueOf(Object)以外,其他valueOf重載都是基於int/long/char/boolean等基本類型參數的。

 

對於非基本類型,即引用類型對象,就要用valueOf(Object)了。來看看這個重載方法的實現。此刻,你應該知道levyId+""當levyId爲null時的值是字符串null的原因了吧!

// in java.lang.String

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

 

使用“+”拼接對象與字符串,首先調用了String#value將對象轉換爲字符串。怎麼得出的這個結論?

下面代碼:

TestObjectStringJoin.java源碼
compile生成的二進制文件TestObjectStringJoin.class
package jstudy;

public class TestObjectStringJoin {
    public static void main(String[] args) {
        Long l = null;
        System.out.println(l + "abc");
    }
}

 

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package jstudy;

public class TestObjectStringJoin {
    public TestObjectStringJoin() {
    }

    public static void main(String[] args) {
        Long l = null;
        System.out.println(l + "abc");
    }
}

 

 

使用javap -v來解析生成的TestObjectStringJoin.class文件裏的字節碼,重點看main方法(如下)。注意到其中有定義StringBuilder對象,並調用了StringBuilder#append(Object)方法。

D:\workspace\sboot\jstudy\target\test-classes\jstudy>javap -v TestObjectStringJoin.class
Classfile /D:/workspace/sboot/jstudy/target/test-classes/jstudy/TestObjectStringJoin.class
  Last modified 2023-6-5; size 858 bytes
  MD5 checksum 02a2129f4d9044c32a956d668b575a20
  Compiled from "TestObjectStringJoin.java"
public class jstudy.TestObjectStringJoin
  ...
{
  ...

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=1
         0: aconst_null
         1: astore_1
         2: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         5: new           #3                  // class java/lang/StringBuilder
         8: dup
         9: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
        12: aload_1
        13: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
        16: ldc           #6                  // String abc
        18: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        21: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        24: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        27: return
      LineNumberTable:
        line 5: 0
        line 6: 2
        line 7: 27
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      28     0  args   [Ljava/lang/String;
            2      26     1     l   Ljava/lang/Long;
    MethodParameters:
      Name                           Flags
      args
}
SourceFile: "TestObjectStringJoin.java"

 

 

總結一下就是,在使用加號 "+" 進行字符串連接時, Java 編譯器在編譯期間會自動插入代碼。在編譯時,Java 編譯器會將加號 "+" 操作符轉換爲使用 `StringBuilder` 或 `StringBuffer` 類的 `append()` 方法來連接字符串。類似於String#valueOf,StringBuilder#append也有許多重載,不同重載的參數包括int/long/char/boolean等基本類型/String/Object。重點來了,重載的append(Object)會調用另一個重載append(String),這期間會調用String.valueOf(Object)將對象轉換成String。關於String#valueOf(Object)方法,上面已經解釋了,它會在對象爲null時返回null字符串。見下圖所示源碼。

 

 

 

下面是與ChatGPT的對話,它對這個知識點的回答並不能令我滿意。anyway,我爲全世界的程序員出了一把力,訓練了一下超強的AI大腦。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章