ChatGPT解决这个技术问题 Extra ChatGPT

Best way to "negate" an instanceof

I was thinking if there exists a better/nicer way to negate an instanceof in Java. Actually, I'm doing something like:

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

But I think that a "beautiful" syntax to do this should exist.

Does anyone know if it exists, and how the syntax look like?

EDIT: By beautiful, I might say something like this:

if(myObject !instanceof SomeClass) { /* do Something */ } // compilation fails
I hate the precedence rules for instanceof so much...
You could always create a variable, something like boolean strIsString = str instanceof String;...
yeah @Baqueta, is a option. But, what differences could happen in memory use in one syntax or another?
How is that a constructive comment?
The Java creators may introduce a new keyword: notinstanceof. Just my two cents ^^

m
maerics

No, there is no better way; yours is canonical.


Actually there can be like: if (!(obj instanceof String)) - Works just fine!
@arun That is the syntax that we all hate, and the original poster is asking how to avoid.
T
ThomasW

I don't know what you imagine when you say "beautiful", but what about this? I personally think it's worse than the classic form you posted, but somebody might like it...

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

About double logic, you could use != true instead of == false :D
Seeing this helps me to understand that if(!(str instanceof String)) is the only right way, and I need to stop thinking alternatives
I like this solution since I am not required to build up a metal stack while reading it!
SonarLint will report an issue about this coding form (as a minor Code Smell), which message is: Remove the literal "false" boolean value.
static code checkers complain about this, but I prefer this, that small ! character is so easy to overlook... And I'd say there is a lot of "us", e.g. StringUtils offers both isBlank() and isNotBlank() compared to !isBlank()...
d
dacwe

You could use the Class.isInstance method:

if(!String.class.isInstance(str)) { /* do Something */ }

... but it is still negated and pretty ugly.


is a little bit better, the excess parenthesis makes the code ugly, IMHO.
Isn't this a lot of slower?
This has different behaviour. The instanceof keyword includes subclasses, the method does not, you need to use Class.isAssignableFrom to replicate the behaviour.
@ChrisCooper This is not true: this method returns true if the specified Object argument is an instance of the represented class (or of any of its subclasses)
K
Koray Tugay

Usually you don't want just an if but an else clause as well.

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

can be written as

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

Or you can write the code so you don't need to know if its a String or not. e.g.

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

can be written as

str = str.toString();

I think this is the best answer here(first part)
This must be an acceptable answer as IntelliJ also suggested this method.
This might just be a "me" problem, but if not and others are in a similar situation, I wanted to at least add the comment that my first reading of the first part was "most of the time it's good practice to always include an else for your if, even if it's just a no-op", which I'd call bad advice. I now realize I misread that, but wanted to drop this note in case anyone else misreads it as well. Great answer!
P
Pablo Grisafi

If you can use static imports, and your moral code allows them

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);
    }
}

And then...

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");
        }
    }    
}

This is just a fluent interface exercise, I'd never use that in real life code! Go for your classic way, it won't confuse anyone else reading your code!


I don't like static imports.. anyway thanks for try to help :)
P
Paul

If you find it more understandable, you can do something like this with 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
}

With Java 11, this should work if (Predicate.not(isInstanceOfTheClass).test(myObject)) { .... Not better, imo, but should work!
t
tibi

ok just my two cents, use a is string method:

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");
}

D
Dharmesh Baldha

You can achieve by doing below way.. just add a condition by adding bracket if(!(condition with instanceOf)) with the whole condition by adding ! operator at the start just the way mentioned in below code snippets.

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

instead of

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

M
Mr5o1

I agree that in most cases the if (!(x instanceof Y)) {...} is the best approach, but in some cases creating an isY(x) function so you can if (!isY(x)) {...} is worthwhile.

I'm a typescript novice, and I've bumped into this S/O question a bunch of times over the last few weeks, so for the googlers the typescript way to do this is to create a typeguard like this:

typeGuards.ts

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

usage

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

I guess the only reason why this might be appropriate in typescript and not regular js is that typeguards are a common convention, so if you're writing them for other interfaces, it's reasonable / understandable / natural to write them for classes too.

There's more detail about user defined type guards like this in the docs