buguge - Keep it simple,stupid

知识就是力量,但更重要的,是运用知识的能力why buguge?

导航

判断对象是否为null,小伙竟然用StringUtils.isEmpty(obj+"")

我在代码走查时,发现下面的代码。其中Line133行的StringUtils.isEmpty(levyId+"")引起了我的注意。levyId是Long,你这样判断Long是否为null,靠谱吗?

 

 

答案是:不靠谱!

当levyId是null时,levyId+""的值是什么? 是字符串null哟~~ 显然,org.apache.commons.lang.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大脑。

 

 

posted on 2023-06-05 14:55  buguge  阅读(138)  评论(0编辑  收藏  举报