在调用instanceof之前需要进行null检查吗?

1602

null instanceof SomeClass会返回false而不是抛出NullPointerException异常。


1
对于任何仅在相同类型的非空对象上成功运行的 Compare、Equals 或类似方法,将其作为“最佳实践”起始(或非常早期)行是“重要的”或至少非常有用的,并且可以在一行中防范“愚蠢的情况”。代码越少,错误越少。 - user1743310
20
就“这个有用吗?”的争议发表一下看法 - 我从未编写过自己的Java代码(因此不太清楚规范在哪里,编译测试也非常困难),但我目前正在手动将Java转换为JavaScript。我的代码在空引用上失败了,搜索后找到了被接受的答案,确认了这是预期行为,并且我缺少了一个隐式的空检查。在我的情况下非常有用。 - Scott Mermelstein
我利用instanceof检查null的事实来实现一个非常紧凑的Java equals()实现,它比我看到由Eclipse和IntelliJ自动生成的实现更清晰易读:https://stackoverflow.com/a/75402885/501113 - chaotic3quilibrium
8个回答

2174
不需要在使用instanceof之前进行空值检查。
如果x为null,则表达式x instanceof SomeClass为false。
Java 11语言规范在第15.20.2节,“类型比较运算符instanceof”中简洁地表达了这一点。 (在instanceof模式匹配引入后,Java 17表达得不太简洁。)
引用规范中的描述:“在运行时,如果关系表达式的值不是null并且引用可以转换为ReferenceType而不会引发ClassCastException,则instanceof运算符的结果为true。否则结果为false。”
因此,如果操作数为null,则结果为false。

441
这个答案比“试一试”更正确,因为“当前行为”与“保证的行为”不同。 - Luke
4
这个问题在Joshua Bloch的《Effective Java》中关于对象相等性的章节中提到 - http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683 - Kevin Meredith
22
具体来说,在第8项中,他指出在equals()方法中,一个instanceof运算符起到两个作用——它验证参数既不为空,又是正确的类型。因此,“你不需要单独进行空值检查”。 - Andy Thomas
5
Java的规范过去和现在都保证了这种行为。我认为Luke的观点涉及到了实验在确定当前保证行为方面的局限性。 - Andy Thomas
4
@GabrielBB这就像是用红笔在红色纸上写字一样。即使它没有意义,由于可以将任意笔与任意纸组合起来,它仍然是可能的。而将“写在同样颜色的纸上”的检查功能实现到笔中会增加技术复杂性,但几乎没有好处。 - Holger
显示剩余6条评论

319

使用空引用作为 instanceof 的第一个操作数将返回 false


295
现在在谷歌上找到这个问题只需要10秒钟。 - PL_kolek
当使用!null作为instanceof的第一个操作数时,也会返回false。很有趣! - MrYellow
@MrYellow 这将是一个语法错误,需要使用括号。 - maraca
这是有效的语法,只是有点令人困惑。 !null 是真值。 - MrYellow
1
@MrYellow 注意问题是关于Java而不是JavaScript或其他具有"truthy"概念的语言。 - Valerio Bozz

85

确实是一个非常好的问题。我刚刚为自己尝试了一下。

public class IsInstanceOfTest {

    public static void main(final String[] args) {

        String s;

        s = "";

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));

        s = null;

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));
    }
}

打印

true
true
false
false

JLS / 15.20.2. Type Comparison Operator instanceof

运行时,如果RelationalExpression的值不为null且引用可以强制转换为ReferenceType而不会引发ClassCastException,则instanceof操作符的结果为true。否则结果为false

API / Class#isInstance(Object)

如果此Class对象表示一个接口,则如果类或指定的Object参数的任何超类实现了该接口,则此方法返回true;否则返回false。如果此Class对象表示基本类型,则此方法返回false


1
有点混乱。因为它说“String s”,所以s是一个字符串,但是s是null,所以s不是一个字符串。那么s到底是什么? - Kai Wang
1
@KaiWang 的s只是一个对象引用变量。它可以引用一个实际存在的对象(""),也可以引用一个(the)null字面引用。 - Jin Kwon
我还是有点困惑。s现在可能为空,但它以后只能指向一个String实例。它不能像Integer一样被指向。所以即使它是null,它仍然是一种String。只是没有太多意义... - Kai Wang
1
@KaiWang 你把变量类型和实际对象类型混淆了。变量不是实例,它们实际上只是指针。无论哪个变量指向它,null 都不是字符串数据。例如,s instanceof String 不等同于 field.getType().equals(String.class) - Matthew Read
3
@KaiWang 你需要想象一下,在调用s instanceof String时,将s替换为实际的值,那么就会变成 "" instanceof Stringnull instanceof String。这样考虑可能更容易理解。 - Timo Türschmann
显示剩余3条评论

28
不是的。如果第一个操作数为null,则instanceof将返回false

25

作为一个小提示:

即使是 (((A)null)instanceof A) 也会返回 false


(如果将 null 进行类型转换看起来令人惊讶,有时候你也不得不这样做,比如在以下情况中:)

TBD

public class Test
{
  public static void test(A a)
  {
    System.out.println("a instanceof A: " + (a instanceof A));
  }

  public static void test(B b) {
    // Overloaded version. Would cause reference ambiguity (compile error)
    // if Test.test(null) was called without casting.
    // So you need to call Test.test((A)null) or Test.test((B)null).
  }
}

那么Test.test((A)null)将打印a instanceof A: false


P.S.:如果你在招聘人员,请不要将此作为面试问题。 :D


7
关于你的PS:如果有人在面试中提供陷阱问题,那么他们的级别太低,不适合担任面试官。任何问题的对错答案都不应该影响面试结果,重要的是围绕这个话题展开的随后的交流 - alife

6
不需要在调用instanceof之前进行null检查。如果其值为null,则始终返回false。
根据Java语言规范中对使用instanceof的说明:
在运行时,如果RelationalExpression的值不为null并且引用可以转换为ReferenceType而不引发ClassCastException,则instanceof运算符的结果为true。否则结果为false。
因此我们可以推断出Java还有一个称为null类型的东西,这个null类型在instanceof运算符中进行了检查,显然会返回false,因为它期望一个特定的类型。
Java编程语言中有两种类型:原始类型和引用类型。根据Java规范中关于类型和值的说明。

还有一种特殊的空类型,表达式null的类型,它没有名称。由于null类型没有名称,因此无法声明null类型变量或将其转换为null类型。null引用是null类型表达式的唯一可能值。null引用始终可以扩展为任何引用类型。

从Java 14开始,特别是在LTS Java 17中,我们拥有了增强的instanceof。我们有模式匹配功能,可以在类型比较后执行类型转换。

例如

public static void main(String[] args) {
    Object testObject = "I am a string";
    List<Object> testList = null;
    if (testList instanceof List) {
        System.out.println("instance of list");
    } else {
        System.out.println("null type");
    }
    //Enhanced instanceof with type conversion - tested with JDK 17
    if (testObject instanceof String str) {
        System.out.println(str.toUpperCase());
    }
}

输出

null type
I AM A STRING

3
  • 在使用instanceof时,不需要进行null检查
  • 在instanceof验证为true后,不需要进行null检查

以下内容是null-safe的:

if(couldbenull instanceof Comparable comp){
   return comp.compareTo(somethingElse);
}

//java < 14
if(couldbenull instanceof Comparable){
   return ((Comparable)couldbenull).compareTo(somethingElse);
}

2
instanceof运算符不需要显式的null检查,因为如果操作数是null,它不会抛出NullPointerException
在运行时,如果关系表达式的值不是null并且引用可以转换为引用类型而不引发类转换异常,则instanceof运算符的结果为true。
如果操作数是null,则instanceof运算符返回false,因此不需要进行显式的null检查。
考虑以下示例:
public static void main(String[] args) {
         if(lista != null && lista instanceof ArrayList) {                     //Violation
                System.out.println("In if block");
         }
         else {
                System.out.println("In else block");
         }
}
instanceof 的正确使用方法如下所示:
public static void main(String[] args) {
      
         if(lista instanceof ArrayList){                     //Correct way
                  System.out.println("In if block");
         }
            else {
                 System.out.println("In else block");
         }  
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接