Найкращий спосіб "заперечувати" 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.