Чи можливо використовувати оператор instanceof в операторі комутатора?


267

У мене виникло питання використання корпусу комутатора для instanceofоб'єкта:

Наприклад: мою проблему можна відтворити на Java:

if(this instanceof A)
    doA();
else if(this instanceof B)
    doB();
else if(this instanceof C)
    doC():

Як це було б реалізовано за допомогою switch...case?


6
Якщо ви дійсно відчуваєте, що вам потрібен перемикач, ви можете хеш-ім'я класу до int і використовувати це, проте слідкуйте за можливими сутичками. Додавання як коментар, а не відповідь, оскільки мені не подобається, що ідея про це фактично використовувалася. Можливо, вам справді потрібен шаблон відвідувачів.
vickirk

1
Станом на java 7, ви навіть можете ввімкнути повністю кваліфіковану назву класу, щоб уникнути таких хеш-сутичок, як вказував @vickirk, але це все ще некрасиво.
Мітья

Відповіді:


225

Це типовий сценарій, коли поліморфізм підтипу допомагає. Виконайте наступне

interface I {
  void do();
}

class A implements I { void do() { doA() } ... }
class B implements I { void do() { doB() } ... }
class C implements I { void do() { doC() } ... }

Тоді ви можете просто зателефонувати do()по this.

Якщо ви не можете змінювати A, Bі C, ви можете застосувати шаблон відвідувачів, щоб досягти того ж.


33
Шаблон відвідувача означає, що A, B і C повинні реалізувати інтерфейс з абстрактним методом, який приймає Visitor як вхідний параметр, що робити, якщо ви не можете змінити A, B, C і жоден з них не реалізує цей інтерфейс?
thermz

21
Останній коментар щодо схеми відвідувачів неправильний. Вам все одно потрібно буде зробити A, B і C реалізацією інтерфейсу.
Бен Терлі

10
На жаль, це не працює, якщо код do () - вимагає середовища хоста (тобто доступу до змінних, яких немає у самому do ()).
мафу

2
Питання @mafu OP стосувалося диспетчеризації на основі типу. Якщо вашому методу do () потрібен більше вклад для відправки, ніж ваша проблема, це ІМХО поза межами обговорюваного тут питання.
jmg

3
ця відповідь передбачає, що ви можете змінювати класи A, B, C, хоча я думаю, що справа полягає в тому, як це зробити без зміни A, B, C, оскільки вони можуть бути в третій частині бібліотеки
cloud_weather

96

якщо ви абсолютно не можете кодувати інтерфейс, ви можете використовувати enum як посередника:

public A() {

    CLAZZ z = CLAZZ.valueOf(this.getClass().getSimpleName());
    switch (z) {
    case A:
        doA();
        break;
    case B:
        doB();
        break;
    case C:
        doC();
        break;
    }
}


enum CLAZZ {
    A,B,C;

}

thx, я також повинен був внести деякі зміни: 1) ініціалізувати кожен ідентифікатор enum з посиланням на Class; 2) затвердити просте ім'я класу за допомогою enum id .toString (); 3) знайти перерахунок через збережену посилання класу на en en id. Я думаю, що це також безпечно.
Сила Водолія

якщо this.getClass (). getSimpleName () не відповідає значенню CLAZZ, він викидає виняток ... краще оточити блоком спробу спіймання, і виняток вважатиметься параметром "за замовчуванням" або "else" перемикач
тетрі

40

Просто створіть Map, де клас є ключовим, а функціональність - лямбда або подібне - значення.

Map<Class,Runnable> doByClass = new HashMap<>();
doByClass.put(Foo.class, () -> doAClosure(this));
doByClass.put(Bar.class, this::doBMethod);
doByClass.put(Baz.class, new MyCRunnable());

// звичайно, рефактор цього, щоб ініціалізувати лише один раз

doByClass.get(getClass()).run();

Якщо вам потрібні перевірені винятки, ніж застосувати функціональний інтерфейс, який викидає виняток, і використовувати його замість Runnable.


3
Найкраще рішення imho, спеціально тому, що це дозволяє легко рефакторингу.
Фейтейра

2
Єдиним недоліком цього рішення є те, що він не може використовувати локальні (методові) змінні в лямбдах (якщо припустити, що це може знадобитися, звичайно).
Сапатеро

1
@zapatero Ви можете просто змінити функцію замість Runnable, передайте екземпляр як параметр, а потім
додайте

Оголошений; це одна з небагатьох відповідей, яка насправді допомагає ОП виконувати те, про що він просить (і так, часто можна переробляти код, чого не потрібно робити instanceof, і ні, мій сценарій, на жаль, не з тих, що легко вписуються в та скринька ...)
Пер Лундберг

@ SergioGutiérrez Дякую Що ж, ця модель повинна бути потрібна лише для зовнішньої бібліотеки. І навіть тоді ви можете просто створити інтерфейс із реалізацією адаптера, але корисно там, де ви хочете, щоб поведінковий DIFF, так би мовити, був більш очевидним. Схоже на маршрутизацію API на вільне відношення до анотацій.
Новатерата

36

Про всяк випадок, якщо хтось прочитає його:

НАЙКРАЩЕ рішення у Java:

public enum Action { 
    a{
        void doAction(...){
            // some code
        }

    }, 
    b{
        void doAction(...){
            // some code
        }

    }, 
    c{
        void doAction(...){
            // some code
        }

    };

    abstract void doAction (...);
}

ВЕЛИКІ переваги такого шаблону:

  1. Ви просто робите це так, як немає (перемикачів немає):

    void someFunction ( Action action ) {
        action.doAction(...);   
    }
  2. У випадку, якщо ви додасте нову дію під назвою "d", ОБОВ'ЯЗКОВО випробувати метод doAction (...)

ПРИМІТКА. Ця модель описана в Блоші Джошуа "Ефективна Java (2-е видання)"


1
приємно! Чи @Overrideвимагається вище кожної реалізації doAction()?
mateuscb

9
Як це рішення "НАЙКРАЩЕ"? Як би ви вирішили, який actionвикористовувати? Зовнішнім екземпляром каскаду, який дзвонить someFunction()з правильним action? Це просто додає ще один рівень непрямості.
PureSpider

1
Ні, це буде зроблено автоматично під час виконання. Якщо ви зателефонуєте до деякихFunction (Action.a), тоді буде викликано a.doAction.
se.solovyev

11
Я цього не розумію. Як би ви могли знати, який перелік використовувати? Як сказав @PureSpider, це здається просто ще одним рівнем роботи.
Джеймс Манес

2
Дуже прикро, що ви не запропонували повного прикладу , наприклад, як зіставити будь-який клас-екземпляр a, b або C до цієї перерахунку. Я спробую віддати Екземпляр цьому Енуму.
Том

21

Ви не можете. Оператор switchможе містити лише caseвисловлювання, які є константами часу компіляції та які оцінюються до цілого числа (До Java 6 та рядка в Java 7).

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

Див. Також Уникнення instanceof в Java


1
Ні, у більшості функціональних мов ви не можете узгоджувати відповідність типів, лише на конструкторах. Принаймні, це правда в ML та Haskell. У Scala та OCaml можливе, але не типове застосування відповідності шаблонів.
jmg

Звичайно, але перевірка конструкцій була б "еквівалентною" описаному вище сценарію.
Карло В. Данго

1
У деяких випадках, але не в цілому.
jmg

Перемикачі також можуть підтримувати перерахунки.
Соломон Учко

"Ви не можете" поглянути на іншу мову, рідко є корисною відповіддю.
Л. Блан

17

Як було обговорено у головних відповідях, традиційний підхід ООП полягає у використанні поліморфізму замість комутатора. Для цього трюку є навіть добре задокументована модель рефакторингу: Замінити умовне поліморфізмом . Щоразу, коли я досягаю цього підходу, я люблю також реалізувати об’єкт Null, щоб забезпечити поведінку за замовчуванням.

Починаючи з Java 8, ми можемо використовувати лямбди та дженерики, щоб дати нам щось знайоме з функціональними програмістами: узгодження шаблонів. Це не основна мовна особливість, але бібліотека Javaslang забезпечує одну реалізацію. Приклад з javadoc :

Match.ofType(Number.class)
    .caze((Integer i) -> i)
    .caze((String s) -> new BigDecimal(s))
    .orElse(() -> -1)
    .apply(1.0d); // result: -1

Це не найприродніша парадигма в світі Java, тому використовуйте її з обережністю. У той час як загальні методи позбавлять вас від необхідності вводити відповідне значення, нам не вистачає стандартного способу розкласти відповідний об'єкт, як, наприклад, у випадках класів Scala .


9

Я знаю, що це дуже пізно, але для майбутніх читачів ...

Остерігайтеся вище підходів, які базуються лише на назві класів A , B , C ...:

Якщо ви не зможете гарантувати, що A , B , C ... (всі підкласи або реалізатори Base ) є остаточними, тоді з підкласами A , B , C ... не буде розглядатися.

Хоча підхід if, elseif, elseif .. повільніший для великої кількості підкласів / реалізаторів, він є більш точним.



8

На жаль, це неможливо вийти з поля, оскільки оператор switch case очікує постійного вираження. Щоб подолати це, одним із способів було б використання значень enum із назвами класів, наприклад

public enum MyEnum {
   A(A.class.getName()), 
   B(B.class.getName()),
   C(C.class.getName());

private String refClassname;
private static final Map<String, MyEnum> ENUM_MAP;

MyEnum (String refClassname) {
    this.refClassname = refClassname;
}

static {
    Map<String, MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
    for (MyEnum instance : MyEnum.values()) {
        map.put(instance.refClassname, instance);
    }
    ENUM_MAP = Collections.unmodifiableMap(map);
}

public static MyEnum get(String name) {
    return ENUM_MAP.get(name);
 }
}

З цим можливо використовувати оператор switch таким чином

MyEnum type = MyEnum.get(clazz.getName());
switch (type) {
case A:
    ... // it's A class
case B:
    ... // it's B class
case C:
    ... // it's C class
}

Я вважаю, що до повного впровадження JEP випуску 8213076 це найчистіший спосіб отримати оператор перемикання на основі типу, не змінюючи цільовий клас.
Рік Шааф


5

Використання таких операторів перемикання не є об'єктно-орієнтованим способом. Натомість вам слід використовувати силу поліморфізму . Просто напишіть

this.do()

Попередньо встановивши базовий клас:

abstract class Base {
   abstract void do();
   ...
}

який є базовим класом для A, Bі C:

class A extends Base {
    void do() { this.doA() }
}

class B extends Base {
    void do() { this.doB() }
}

class C extends Base {
    void do() { this.doC() }
}

@jmg suggeests ( stackoverflow.com/questions/5579309/switch-instanceof / ... ) , використовуючи інтерфейс замість абстрактного базового класу. Це може бути вищим у деяких циркультурностях.
Raedwald

5

Це буде працювати швидше і матиме сенс у випадку
- у вас відносно багато "випадків"
- процес виконується у контексті, залежно від продуктивності

public <T> T process(Object model) {
    switch (model.getClass().getSimpleName()) {
        case "Trade":
            return processTrade();
        case "InsuranceTransaction":
            return processInsuranceTransaction();
        case "CashTransaction":
            return processCashTransaction();
        case "CardTransaction":
            return processCardTransaction();
        case "TransferTransaction":
            return processTransferTransaction();
        case "ClientAccount":
            return processAccount();
        ...
        default:
            throw new IllegalArgumentException(model.getClass().getSimpleName());
    }
}

1
Це не те саме, що робити instanceof, оскільки це працює лише в тому випадку, якщо клас комутації використовується для перемикання, але він не буде працювати для інтерфейсів / Abstractclass /
superclasses

так, це не так
Майк

Доклавши зусиль, окрім коментаря @ lifesoWeather, ви також пропускаєте безпеку типу, яку ви зазвичай маєте, оскільки ця відповідь використовує жорсткі коди, а не посилання на класи. Зробити помилку друку досить просто, особливо якщо вам потрібно буде розширити цю функціональність за допомогою повних канонічних імен, якщо тут було якесь накладення назви класів з різними іменами пакетів.Edit: fix typo (що ніби доводить мою думку)
Rik Schaaf

4

Ви не можете перемикатися, що працює лише з байтовими, короткими, char, int, рядковими та переліченими типами (і об'єктними версіями примітивів, це також залежить від вашої версії java. Strings можна switchредагувати в java 7)


Ви не можете ввімкнути Strings на Java 6. І ви не можете ввімкнути "об'єктні версії примітивів".
Лукас Едер

@Bozho Я сказав, що це залежить від вашої версії Java, в Java 7 ви можете вмикати Strings.
Тнем

@Lukas Eder перевірить свою специфікацію Java
Tnem,

4

Мені особисто подобається такий код Java 1.8:

    mySwitch("YY")
            .myCase("AA", (o) -> {
                System.out.println(o+"aa");
            })
            .myCase("BB", (o) -> {
                System.out.println(o+"bb");
            })
            .myCase("YY", (o) -> {
                System.out.println(o+"yy");
            })
            .myCase("ZZ", (o) -> {
                System.out.println(o+"zz");
            });

Виведе:

YYyy

У зразковому коді використовуються рядки, але ви можете використовувати будь-який тип об'єкта, включаючи клас. напр.myCase(this.getClass(), (o) -> ...

Потрібен такий фрагмент:

public Case mySwitch(Object reference) {
    return new Case(reference);
}

public class Case {

    private Object reference;

    public Case(Object reference) {
        this.reference = reference;
    }

    public Case myCase(Object b, OnMatchDo task) {
        if (reference.equals(b)) {
            task.task(reference);
        }
        return this;
    }
}

public interface OnMatchDo {

    public void task(Object o);
}

4

Тепер Java дозволяє перемикатися в режимі ОП. Вони називають це узгодження шаблонів для перемикання. Наразі він знаходиться в стадії проекту, але, бачачи, скільки роботи вони нещодавно вводять у вимикачі, я думаю, це пройде. Приклад, наведений у JEP:

String formatted;
switch (obj) {
    case Integer i: formatted = String.format("int %d", i); break;
    case Byte b:    formatted = String.format("byte %d", b); break;
    case Long l:    formatted = String.format("long %d", l); break;
    case Double d:  formatted = String.format("double %f", d); break;
    case String s:  formatted = String.format("String %s", s); break
    default:        formatted = obj.toString();
}  

або використовуючи їх лямбда-синтаксис і повертаючи значення

String formatted = 
    switch (obj) {
        case Integer i -> String.format("int %d", i)
        case Byte b    -> String.format("byte %d", b);
        case Long l    -> String.format("long %d", l); 
        case Double d  -> String.format("double %f", d); 
        case String s  -> String.format("String %s", s); 
        default        -> obj.toString();
    };

так чи інакше вони робили класні речі з перемикачами.


3

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

Для мене логіка повинна бути в написаному в операторі комутатора, а не в самому об'єкті. Це було моє рішення:

ClassA, ClassB, and ClassC implement CommonClass

Інтерфейс:

public interface CommonClass {
   MyEnum getEnumType();
}

Enum:

public enum MyEnum {
  ClassA(0), ClassB(1), ClassC(2);

  private int value;

  private MyEnum(final int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }

Імпл .:

...
  switch(obj.getEnumType())
  {
    case MyEnum.ClassA:
      ClassA classA = (ClassA) obj;
    break;

    case MyEnum.ClassB:
      ClassB classB = (ClassB) obj;
    break;

    case MyEnum.ClassC:
      ClassC classC = (ClassC) obj;
    break;
  }
...

Якщо ви знаходитесь на java 7, ви можете поставити рядкові значення для enum, і блок корпусу комутатора все одно буде працювати.


valueПоле є зайвим , якщо ви хочете , щоб відрізнити константи перерахувань - ви можете використовувати константи безпосередньо (як і ви).
користувач905686

2

Як щодо цього?

switch (this.name) 
{
  case "A":
    doA();
    break;
  case "B":
    doB();
    break;
  case "C":
    doC();
    break;
  default:
    console.log('Undefined instance');
}

3
Слід зазначити, що це працює лише на Java 7. І що вам потрібно зателефонувати this.getSimpleName()Не впевнений, чи афіша плутається з JS (так, він використовує консоль, хе-хе).
pablisco

5
У цьому виникає проблема випадання прозорості для вихідних кодів. Тобто, ваш IDE не зможе зберегти референтну цілісність. Припустимо, ви хочете перейменувати своє ім’я. Відображення - зло.
Валь

1
Не чудова ідея. Назви класів не є унікальними, якщо у вас є кілька завантажувачів класів.
Дорадус

Перерви, коли йдеться про стиснення коду (→ ProGuard)
Маттіас Ронге

1

Я думаю, що є причини використовувати оператор switch. Якщо ви, можливо, використовуєте код, створений xText. Або інший клас, створений ЕМП класами.

instance.getClass().getName();

повертає рядок Ім'я впровадження класу. тобто: org.eclipse.emf.ecore.util.EcoreUtil

instance.getClass().getSimpleName();

повертає просту репресію, тобто: EcoreUtil


Ви не можете використовувати його switchяк caseумову, оскільки це не постійне значення
B-GangsteR

1

Якщо вам потрібно "переключити" через тип класу "цього" об'єкта, ця відповідь найкраща https://stackoverflow.com/a/5579385/2078368

Але якщо вам потрібно застосувати "перемикач" на будь-яку іншу змінну. Я б запропонував інше рішення. Визначте наступний інтерфейс:

public interface ClassTypeInterface {
    public String getType();
}

Реалізуйте цей інтерфейс у кожному класі, який ви хочете "переключити". Приклад:

public class A extends Something implements ClassTypeInterface {

    public final static String TYPE = "A";

    @Override
    public String getType() {
        return TYPE;
    }
}

Після цього ви можете використовувати його наступним чином:

switch (var.getType()) {
    case A.TYPE: {
        break;
    }
    case B.TYPE: {
        break;
    }
    ...
}

Єдине, про що вам слід подбати - зберегти унікальні "типи" для всіх класів, що реалізують ClassTypeInterface. Це не велика проблема, тому що в разі будь-якого перехрестя ви отримуєте помилку часу компіляції для оператора "switch-case".


Замість використання String для TYPE, ви можете використовувати перерахунок, і унікальність гарантована (як це зроблено у цій відповіді ). Однак при будь-якому з підходів вам доведеться переробляти в двох місцях під час перейменування.
user905686

@ user905686 перейменувати що? У поточному прикладі тип "A" визначається всередині класу Something, щоб мінімізувати кількість коду. Але в реальному житті ви, очевидно, повинні визначити це зовні (в якомусь загальному місці), і з подальшим рефакторингом не виникає жодних проблем.
Сергій Кривенков

Я маю на увазі перейменування класу А. Автоматичний рефакторинг може не включати змінну TYPE = "A"при перейменуванні. Особливо, якщо він знаходиться поза відповідним класом, його можна також забути, роблячи це вручну. IntelliJ насправді також знаходить зустріч назви класу в рядках або коментарях, але це лише пошук тексту (замість того, щоб дивитись на синтаксичне дерево) і, таким чином, включає помилкові позитиви.
user905686

@ user905686 - це лише приклад для візуалізації ідеї. Не використовуйте String для визначень типів у реальному проекті, оголосьте деякі власники класів MyTypes з цілими константами (або enum) та використовуйте їх у класах, що реалізують ClassTypeInterface.
Сергій Кривенков

1

Ось функціональний спосіб її виконання в Java 8 за допомогою http://www.vavr.io/

import static io.vavr.API.*;
import static io.vavr.Predicates.instanceOf;
public Throwable liftRootCause(final Throwable throwable) {
        return Match(throwable).of(
                Case($(instanceOf(CompletionException.class)), Throwable::getCause),
                Case($(instanceOf(ExecutionException.class)), Throwable::getCause),
                Case($(), th -> th)
        );
    }

1

Хоча неможливо написати оператор перемикання, можливо розгалуження на конкретну обробку для кожного заданого типу. Один із способів зробити це - використовувати стандартний механізм подвійної диспетчеризації. Прикладом, коли ми хочемо «переключитися» на основі типу, є перетворювач Jersey Exception, де нам потрібно відобразити безліч винятків із відповідей на помилки. Хоча для цього конкретного випадку існує, мабуть, кращий спосіб (тобто використання поліморфного методу, який переводить кожен виняток у відповідь на помилку), використання подвійного механізму відправки все ще корисне і практичне.

interface Processable {
    <R> R process(final Processor<R> processor);
}

interface Processor<R> {
    R process(final A a);
    R process(final B b);
    R process(final C c);
    // for each type of Processable
    ...
}

class A implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

class B implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

class C implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

Тоді де колись потрібен «перемикач», ви можете зробити це так:

public class LogProcessor implements Processor<String> {
    private static final Logger log = Logger.for(LogProcessor.class);

    public void logIt(final Processable base) {
        log.info("Logging for type {}", process(base));
    }

    // Processor methods, these are basically the effective "case" statements
    String process(final A a) {
        return "Stringifying A";
    }

    String process(final B b) {
        return "Stringifying B";
    }

    String process(final C c) {
        return "Stringifying C";
    }
}

Це виглядає як шаблон для відвідувачів, які вже обговорювалися в цій відповіді: stackoverflow.com/a/5579385
typeracer

0

Створіть Enum з іменами класів.

public enum ClassNameEnum {
    A, B, C
}

Знайдіть назву класу об’єкта. Напишіть справу перемикача над перерахунком.

private void switchByClassType(Object obj) {

        ClassNameEnum className = ClassNameEnum.valueOf(obj.getClass().getSimpleName());

        switch (className) {
            case A:
                doA();
                break;
            case B:
                doB();
                break;
            case C:
                doC();
                break;
        }
    }
}

Сподіваюсь, це допомагає.


2
На відміну від такого підходу, коли з'єднання між константами перерахунків і класами здійснюється явно, ви з'єднуються неявно за назвою класу. Це порушить ваш код, коли ви перейменовуєте лише одну константу enum або клас, тоді як інший підхід все ще буде працювати.
користувач905686

0

Рамка моделювання Eclipse має цікаву ідею, яка також враховує спадщину. Основна концепція визначена в інтерфейсі Switch : перемикання здійснюється шляхом виклику методу doSwitch .

Що насправді цікаво - це реалізація. Для кожного типу відсотків:

public T caseXXXX(XXXX object);

метод повинен бути реалізований (з типовою реалізацією, що повертає нуль). Реалізація doSwitch спробує викликати всі об'єкти caseXXX на об'єкт для всієї його ієрархії типів. Щось у рядках:

BaseType baseType = (BaseType)object;
T result = caseBaseType(eAttribute);
if (result == null) result = caseSuperType1(baseType);
if (result == null) result = caseSuperType2(baseType);
if (result == null) result = caseSuperType3(baseType);
if (result == null) result = caseSuperType4(baseType);
if (result == null) result = defaultCase(object);
return result;

Фактичний фреймворк використовує цілий ідентифікатор для кожного класу, тому логіка насправді є чистим перемикачем:

public T doSwitch(Object object) {
    return doSwitch(object.class(), eObject);
}

protected T doSwitch(Class clazz, Object object) {
    return doSwitch(getClassifierID(clazz), object);
}

protected T doSwitch(int classifierID, Object theObject) {
    switch (classifierID) {
    case MyClasses.BASETYPE:
    {
      BaseType baseType = (BaseType)object;
      ...
      return result;
    }
    case MyClasses.TYPE1:
    {
      ...
    }
  ...

Ви можете ознайомитись з повною реалізацією ECoreSwitch, щоб отримати кращу ідею.


-1

є ще простіший спосіб емуляції структури комутатора, який використовує instanceof, ви робите це, створюючи блок коду у своєму методі та називаючи його міткою. Тоді ви використовуєте if структури для імітації випадок справи. Якщо виправданий випадок, ви використовуєте перерву LABEL_NAME, щоб вийти зі своєї структури імпровізованих комутаторів.

        DEFINE_TYPE:
        {
            if (a instanceof x){
                //do something
                break DEFINE_TYPE;
            }
            if (a instanceof y){
               //do something
                break DEFINE_TYPE;
            }
            if (a instanceof z){
                // do something
                break DEFINE_TYPE;
            }
        }

Чим це краще, ніж if... else ifкод, наданий ОП?
друкарка

Просто для детального пояснення попереднього коментаря: те, що ви пропонуєте, по суті, замінити if... else ifна "goto" заяви, що є неправильним способом реалізації потоку управління на таких мовах, як Java.
друкарка
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.