supported - switch java пример




Почему я не могу использовать оператор switch на String? (10)

Будет ли эта функциональность переведена в более позднюю версию Java?

Может ли кто-нибудь объяснить, почему я не могу это сделать, как в техническом способе работы оператора Java?


В течение многих лет мы использовали для этого препроцессор (n open source).

//#switch(target)
case "foo": code;
//#end

Предварительно обработанные файлы называются Foo.jpp и обрабатываются в Foo.java с помощью скрипта ant.

Преимущество заключается в том, что он обрабатывается в Java, который работает на 1.0 (хотя обычно мы поддерживаем только 1.4). Также было намного проще сделать это (много строковых переключателей) по сравнению с fudging его с перечислениями или другими обходными решениями - код был намного легче читать, поддерживать и понимать. IIRC (на данный момент не может предоставлять статистические данные или технические аргументы), он также быстрее, чем естественные эквиваленты Java.

Недостатки в том, что вы не редактируете Java, так что это немного больше рабочего процесса (редактирование, обработка, компиляция / тестирование), а среда IDE свяжется с Java, которая немного запутана (коммутатор становится серией логических шагов if / else) и порядок контактов выключателя не поддерживается.

Я бы не рекомендовал его для 1.7+, но это полезно, если вы хотите запрограммировать Java, который нацелен на более ранние JVM (поскольку у публики Joe редко установлена ​​последняя версия).

Вы можете получить его из SVN или просмотреть код онлайн . Вам понадобится EBuild для его создания как есть.


Джеймс Карран лаконично говорит: «Переключатели на основе целых чисел могут быть оптимизированы для очень эффективного кода. Переключатели на основе другого типа данных могут быть скомпилированы только в ряд операторов if (). По этой причине C & C ++ разрешает только переключатели на целочисленные типы, так как это было бессмысленно с другими типами ».

Мое мнение, и только в том, что, как только вы начнете включать не-примитивы, вам нужно начать думать о «равных» по сравнению с «==». Во-первых, сравнение двух строк может быть довольно продолжительной процедурой, добавляя к проблемам производительности, о которых говорилось выше. Во-вторых, если есть включение строк, будет требоваться включение строк, игнорирующих регистр, включение строк с учетом / игнорирование локали, включение строк на основе регулярных выражений .... Я бы одобрил решение, которое сэкономило много времени для языковые разработчики за счет небольшого количества времени для программистов.


Если вы не используете JDK7 или выше, вы можете использовать hashCode() для имитации. Поскольку String.hashCode() обычно возвращает разные значения для разных строк и всегда возвращает равные значения для равных строк, он достаточно надежный (разные строки могут выдавать один и тот же хеш-код как @Lii, упомянутый в комментарии, например, "FB" и "Ea" "FB" "Ea" ) См. documentation .

Таким образом, код будет выглядеть так:

String s = "<Your String>";

switch(s.hashCode()) {
case "Hello".hashCode(): break;
case "Goodbye".hashCode(): break;
}

Таким образом, вы технически включаете int .

Кроме того, вы можете использовать следующий код:

public final class Switch<T> {
    private final HashMap<T, Runnable> cases = new HashMap<T, Runnable>(0);

    public void addCase(T object, Runnable action) {
        this.cases.put(object, action);
    }

    public void SWITCH(T object) {
        for (T t : this.cases.keySet()) {
            if (object.equals(t)) { // This means that the class works with any object!
                this.cases.get(t).run();
                break;
            }
        }
    }
}

Если у вас есть место в вашем коде, где вы можете включить String, тогда может быть лучше реорганизовать String как перечисление возможных значений, которые вы можете включить. Конечно, вы ограничиваете потенциальные значения строк, которые вы можете иметь, для тех, которые перечислены, что может быть или не быть желательным.

Конечно, в вашем перечислении может быть запись для «другого» и метода fromString (String), тогда вы могли бы

ValueEnum enumval = ValueEnum.fromString(myString);
switch (enumval) {
   case MILK: lap(); break;
   case WATER: sip(); break;
   case BEER: quaff(); break;
   case OTHER: 
   default: dance(); break;
}

Коммутаторы на основе целых чисел могут быть оптимизированы для очень эффективного кода. Переключатели на основе другого типа данных могут быть скомпилированы только в ряд операторов if ().

По этой причине C & C ++ разрешает только переключатели на целочисленные типы, поскольку это было бессмысленно с другими типами.

Дизайнеры C # решили, что стиль был важен, даже если не было никакого преимущества.

Дизайнеры Java, по-видимому, думали, как дизайнеры C.


Не очень красиво, но вот еще один способ для Java 6 и ниже:

String runFct = 
        queryType.equals("eq") ? "method1":
        queryType.equals("L_L")? "method2":
        queryType.equals("L_R")? "method3":
        queryType.equals("L_LR")? "method4":
            "method5";
Method m = this.getClass().getMethod(runFct);
m.invoke(this);

Операторы switch с String были реализованы в Java SE 7 , по крайней мере, через 16 лет bugs.sun.com/bugdatabase/view_bug.do?bug_id=1223179 Явная причина задержки не была предоставлена, но, скорее всего, это связано с производительностью.

Внедрение в JDK 7

Эта функция теперь реализована в javac с процессом «обезжиривания»; чистый синтаксис высокого уровня с использованием String констант в case объявления разворачиваются во время компиляции в более сложный код, следуя шаблону. Полученный код использует команды JVM, которые всегда существовали.

При компиляции switch со String случаями преобразуется в два переключателя. Первая отображает каждую строку в уникальное целое число - его положение в исходном коммутаторе. Это делается путем первого включения хэш-кода метки. Соответствующим случаем является оператор if который проверяет равенство строк; если в хеше есть столкновение, тест является каскадным if-else-if . Второй переключатель отражает это в исходном исходном коде, но заменяет метки меток соответствующими позициями. Этот двухэтапный процесс упрощает сохранение управления потоком исходного коммутатора.

Переключатели в JVM

Для дополнительной технической глубины на switch вы можете обратиться к спецификации JVM, где описывается компиляция операторов switch . В двух словах есть две разные команды JVM, которые могут использоваться для коммутатора, в зависимости от разреженности констант, используемых в этих случаях. Оба зависят от использования целочисленных констант для каждого случая для эффективного выполнения.

Если константы плотны, они используются в качестве индекса (после вычитания самого низкого значения) в таблицу указателей инструкций - инструкцию tableswitch .

Если константы разрежены, выполняется двоичный поиск для правильного случая - инструкция lookupswitch .

При деаурации switch на объектах String обе команды, вероятно, будут использоваться. lookupswitch подходит для первого переключателя хэш-кодов, чтобы найти исходное положение корпуса. Результирующий ординал является естественным приложением для tableswitch .

Обе инструкции требуют, чтобы целочисленные константы, назначенные каждому случаю, сортировались во время компиляции. Во время выполнения, в то время как производительность O(1) tableswitch обычно лучше, чем производительность tableswitch O(log(n)) , для этого требуется некоторый анализ, чтобы определить, достаточно ли таблицы достаточно, чтобы оправдать компромисс между пространством и временем. Билл Веннерс написал замечательную статью, которая описывает это более подробно, а также под капотом смотрят другие инструкции управления потоком Java.

До JDK 7

До JDK 7 enum могло аппроксимировать переключатель на основе String . Это использует статический метод valueOf сгенерированный компилятором для каждого типа enum . Например:

Pill p = Pill.valueOf(str);
switch(p) {
  case RED:  pop();  break;
  case BLUE: push(); break;
}

Помимо приведенных выше хороших аргументов, я добавлю, что многие люди сегодня рассматривают switch как устаревшее остальное процессуальное прошлое Java (обратно в C).

Я не полностью разделяю это мнение, я думаю, что switch может иметь свою полезность в некоторых случаях, по крайней мере, из-за его скорости, и в любом случае это лучше, чем некоторые серии каскадных чисел, else if я видел в некотором коде ...

Но действительно, стоит посмотреть на случай, когда вам нужен коммутатор, и посмотреть, не может ли он быть заменен чем-то большим OO. Например, перечисления в Java 1.5+, возможно, HashTable или какая-то другая коллекция (когда-то я сожалею, что у нас нет (анонимных) функций как гражданина первого класса, как в Lua - у которого нет ключа - или JavaScript) или даже полиморфизма.


Это бриз в Groovy; Я вставляю groovy jar и создаю классный класс утилиты, чтобы делать все эти вещи и многое другое, которое я нахожу раздражающим для себя на Java (поскольку я застрял с использованием Java 6 на предприятии).

it.'p'.each{
switch ([email protected]()){
   case "choclate":
     myholder.myval=(it.text());
     break;
     }}...

public class StringSwitchCase { 

    public static void main(String args[]) {

        visitIsland("Santorini"); 
        visitIsland("Crete"); 
        visitIsland("Paros"); 

    } 

    public static void visitIsland(String island) {
         switch(island) {
          case "Corfu": 
               System.out.println("User wants to visit Corfu");
               break; 
          case "Crete": 
               System.out.println("User wants to visit Crete");
               break; 
          case "Santorini": 
               System.out.println("User wants to visit Santorini");
               break; 
          case "Mykonos": 
               System.out.println("User wants to visit Mykonos");
               break; 
         default: 
               System.out.println("Unknown Island");
               break; 
         } 
    } 

} 




switch-statement