Найкращий спосіб "заперечувати" instanceof


409

Я думав, чи існує кращий / приємніший спосіб відмовити instanceofв Java. Насправді я роблю щось на кшталт:

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

Але я думаю, що "красивий" синтаксис для цього повинен існувати.

Хтось знає, чи існує він, і як виглядає синтаксис?


EDIT: За гарним, я можу сказати щось подібне:

if(str !instanceof String) { /* do Something */ } // compilation fails

24
Я так ненавиджу правила пріоритету instanceof...
luiscubal

4
Ви завжди можете створити змінну, щось на зразок boolean strIsString = str instanceof String;...
vaughandroid

так @Baqueta, це варіант. Але, які відмінності можуть статися у використанні пам'яті в тому чи іншому синтаксисі?
caarlos0

2
Як це конструктивний коментар?
Лаут

2
Творці Java можуть ввести нове ключове слово: notinstanceof . Всього два мої центи ^^
Стефан

Відповіді:



132

Я не знаю, що ти уявляєш, коли кажеш "красиво", але що з цим? Я особисто думаю, що це гірше класичної форми, яку ви розмістили, але комусь це може сподобатися ...

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

2
Про подвійну логіку ви можете використовувати != trueзамість == false: D
jupi

Бачачи це, мені допомагає зрозуміти, що if(!(str instanceof String)) це єдиний правильний шлях, і мені потрібно перестати думати альтернативи
Вікаш,

Мені подобається це рішення, оскільки мені не потрібно збирати металевий стек під час його читання!
JaM

59

Ви можете використовувати Class.isInstanceметод:

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

... але це все-таки заперечується і досить потворно.


5
трохи краще, надлишок дужок робить код некрасивим, IMHO.
caarlos0

Хіба це не набагато повільніше?
maxammann

4
Це по-різному. Ключове слово instanceof включає підкласи, метод цього не робить, вам потрібно використовувати Class.isAssignableFrom для реплікації поведінки.
Кріс Купер

7
@ChrisCooper Це неправда:this method returns true if the specified Object argument is an instance of the represented class (or of any of its subclasses)
Natix

24

Зазвичай ви також не хочете, ifа лише elseзастереження.

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

можна записати як

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

Або ви можете написати код, щоб не потрібно було знати, чи це String чи ні. напр

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

можна записати як

str = str.toString();

12

Якщо ви можете використовувати статичний імпорт, і ваш моральний код дозволяє це

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

4

Якщо вам здається більш зрозумілим, ви можете зробити щось подібне з 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)) { .... Не краще, imo, але треба працювати!
Патрік М

3

добре, тільки мої два центи, використовуйте метод 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");
}

0

Ви можете досягти цього, зробивши нижче. Просто додайте умову, додавши дужку if(!(condition with instanceOf))з усією умовою, додавши !оператор на початку точно так, як зазначено в фрагментах коду нижче.

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

замість

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

0

Я погоджуюся, що в більшості випадків if (!(x instanceof Y)) {...}це найкращий підхід, але в деяких випадках створення isY(x)функції, щоб ви могли if (!isY(x)) {...}, варто.

Я початківець машинопису, і я наткнувся на це питання S / O протягом кількох останніх тижнів, так що для googlers спосіб друкарського способу зробити це - створити подібний захист типу:

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

Я здогадуюсь, що єдиною причиною, чому це може бути доречно в машинописі, а не регулярних js, є те, що типові охоронці є звичайною умовою, тому якщо ви пишете їх для інших інтерфейсів, доцільно / зрозуміло / природно писати їх і для класів.

Більш детально про захисні типи, визначені користувачем, є в документах

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.