如何最好地“否定”instanceof?

541

我在想是否存在一种更好/更优雅的方式来否定Java中的instanceof。 实际上,我的做法是这样的:

if(!(myObject instanceof SomeClass)) { /* do Something */ }

但我认为应该存在一种“优美”的语法来实现这一点。

有人知道是否存在,以及语法是什么样的吗?


编辑: 我的意思是像这样的东西:

if(myObject !instanceof SomeClass) { /* do Something */ } // compilation fails

6
您可以创建一个变量,例如 boolean strIsString = str instanceof String;... - vaughandroid
是的 @Baqueta,这是一个选项。但是,在使用不同语法时,内存使用可能会有什么不同呢? - caarlos0
1
你的例子不好,因为String不能有子类,所以你的例子基本上是一个isNull检查。 - David Balažic
9个回答

400

不,没有更好的方式;你的方法是规范的。


1
实际上,可以这样写:if (!(obj instanceof String)) - 完全没问题! - arun
4
那是我们都讨厌的语法,原帖的作者正在问如何避免它。 - Ian Boyd

164

我不知道你在说“美丽”时想象的是什么,但这个怎么样?我个人认为它比你发布的经典形式更差,但有些人可能会喜欢...

if (str instanceof String == false) { /* ... */ }

6
关于双重逻辑,你可以使用“!= true”代替“== false” :D - jupi
4
看到这个,我明白if(!(str instanceof String))是唯一正确的方式,我需要停止思考其他替代方案。 - Vikash
我喜欢这个解决方案,因为在阅读它时不需要构建金属堆栈! - JaM
SonarLint将会报告一个关于这个代码格式的问题(作为一个轻微的代码异味),其信息是:移除字面值“false”的布尔值。 - Ray Chen
静态代码检查器对此抱怨,但我更喜欢这样做,那个小的 ! 字符很容易被忽视...而且我会说有很多像我们一样的人,例如 StringUtils 提供了 isBlank()isNotBlank(),相比之下 !isBlank() 就没有这么好用了... - Betlista
实际上可以这样写:if (!(obj instanceof String)) - 完全没问题! - arun

65
你可以使用Class.isInstance方法:
if(!String.class.isInstance(str)) { /* do Something */ }

...但它仍然被否定且相当丑陋。


5
个人认为,去掉多余的括号会使代码更简洁易读。 - caarlos0
1
这不是慢了很多吗? - maxammann
4
这有不同的行为。instanceof 关键字包括子类,而方法则不包括,您需要使用 Class.isAssignableFrom 来复制此行为。 - Chris Cooper
9
@ChrisCooper,这并不是真的:“如果指定的Object参数是所代表类的实例(或其任何子类的实例),则此方法返回true”。 - Natix

32

通常情况下,你不仅需要一个if语句,还需要一个else子句。

if(!(str instanceof String)) { /* do Something */ } 
else { /* do something else */ }

可以写成

if(str instanceof String) { /* do Something else */ } 
else { /* do something */ }

或者你可以编写代码,使其不需要知道它是否为字符串类型。例如:

if(!(str instanceof String)) { str = str.toString(); } 

可以写成

str = str.toString();

我认为这是最好的答案(前半部分)。 - Jawad El Fou
这应该是一个可接受的答案,因为IntelliJ也建议使用这种方法。 - Udhaya
这可能只是我的问题,但如果不是,而其他人处于类似的情况,我想至少添加一条评论:我第一次阅读第一部分时的理解是“大多数情况下,最好始终为您的if包括一个else,即使它只是一个无操作”,我认为这是错误的建议。我现在意识到我误读了,但是希望放下这个注释,以防其他人也会误读。非常好的答案! - acat

13

如果您可以使用静态导入,并且您的道德准则允许它们

public class ObjectUtils {
    private final Object obj;
    private ObjectUtils(Object obj) {
        this.obj = obj;
    }

    public static ObjectUtils thisObj(Object obj){
        return new ObjectUtils(obj);
    }

    public boolean isNotA(Class<?> clazz){
        return !clazz.isInstance(obj);
    }
}

然后...

import static notinstanceof.ObjectUtils.*;

public class Main {

    public static void main(String[] args) {
        String a = "";
        if (thisObj(a).isNotA(String.class)) {
            System.out.println("It is not a String");
        }
        if (thisObj(a).isNotA(Integer.class)) {
            System.out.println("It is not an Integer");
        }
    }    
}

这只是一个流畅接口的练习,我在实际代码中永远不会使用它!
按照你经典的方式去做,这不会让其他读你代码的人感到困惑!


我不喜欢静态导入...无论如何,还是谢谢你的帮助 :) - caarlos0

6

如果您认为这样更易于理解,您可以使用Java 8做如下:

public static final Predicate<Object> isInstanceOfTheClass = 
    objectToTest -> objectToTest instanceof TheClass;

public static final Predicate<Object> isNotInstanceOfTheClass = 
    isInstanceOfTheClass.negate(); // or objectToTest -> !(objectToTest instanceof TheClass)

if (isNotInstanceOfTheClass.test(myObject)) {
    // do something
}

1
使用Java 11,这个应该可以工作:if (Predicate.not(isInstanceOfTheClass).test(myObject)) { ...}。在我看来并不更好,但应该可以正常工作! - Patrick M

3

好的,这是我自己的意见,使用一个 is string 方法:

public static boolean isString(Object thing) {
    return thing instanceof String;
}

public void someMethod(Object thing){
    if (!isString(thing)) {
        return null;
    }
    log.debug("my thing is valid");
}

你的代码甚至无法编译。 - jmizv

1
我认为在大多数情况下,if (!(x instanceof Y)) {...} 是最好的方法,但有些情况下创建一个 isY(x) 函数,这样你就可以使用 if (!isY(x)) {...} 是值得的。
我是一个 TypeScript 新手,在过去几周里,我遇到了这个 S/O 问题很多次,所以对于那些使用 TypeScript 的人来说,创建一个像这样的类型保护是正确的:

typeGuards.ts

export function isHTMLInputElement (value: any): value is HTMLInputElement {
  return value instanceof HTMLInputElement
}

用法

if (!isHTMLInputElement(x)) throw new RangeError()
// do something with an HTMLInputElement

我猜唯一的原因是这在Typescript中合适而在普通JS中不合适,是因为类型守卫是一个常见的约定,所以如果你为其他接口编写它们,那么也合理/可理解/自然地为类编写它们。
有关用户定义类型守卫的更多详细信息,请参阅文档中的链接

1

您可以通过以下方式实现...只需添加一个条件,通过在整个条件中添加括号if(!(condition with instanceOf))并在开头添加!运算符,就像下面的代码片段中所述。

if(!(str instanceof String)) { /* do Something */ } // COMPILATION WORK

而不是

if(str !instanceof String) { /* do Something */ } // COMPILATION FAIL

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