Почему оператор switchcase в Java работает так?

Почему оператор case switch в Java принимает только целочисленные, короткие, байт и только символы, а не другие типы данных? Какая может быть польза? Пожалуйста, объясните подробно.

Ответ 1

Обычно вопросы дизайна языка сводятся к "потому, что дизайнеры решили это сделать". Это еще один пример того времени.

Но у Java есть некоторые истоки в C, которые сделали то же самое, и в 80 это решение было объяснено мне как потому, что тогда компилятор мог превратить коммутатор в таблицу перехода. В основном каждый блок кода-кода помещается в таблицу, а switch становится проверкой диапазона, за которой следует поиск таблицы (обычно индексируется в массив или по крайней мере связанный список массивов), используя значение, которое вы передаете, чтобы получить адрес, а затем переходите к этому адресу. Только целые числа имеют смысл в этом сценарии. Помните, что компьютеры не всегда были такими быстрыми, как сейчас. C был разработан в начале 70-х годов на основе работы в конце 60-х, когда компьютеры были намного медленнее.

Некоторые языки в той же синтаксической традиции, что и Java и C, такие как JavaScript, делают switch просто еще одним способом записи if...else/if...else и не ограничивают тип, проверяемый на интегральные типы, возможно, потому, что, будучи разработанным в 90-е годы это стало реалистичным вариантом. Или, может быть, только потому, что разработчик JavaScript (Брендан Эйх) предпочитал это именно так.


Ниже Baadshah спрашивает:

Из любопытства: Тогда теперь как его поддерживающие Струны??? не могли бы вы дать какую-то идею?

Сначала отпустите назад и посмотрите на случай int:

  num = Integer.parseInt(args[0]);
  switch (num) {
      case 1:
          System.out.println("You used the special value one");
          break;
      case 42:
          System.out.println("You used the special value forty-two");
          break;
      case 67:
          System.out.println("You used the special value sixty-seven");
          break;
      default:
          System.out.println("You used the a non-special value " + num);
          break;
  }

Это создает байт-код следующим образом:

 19: iload_2       
 20: lookupswitch  { // 3
                1: 56
               42: 67
               67: 78
          default: 89
     }
 56: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
 59: ldc           #9   // String You used the special value one
 61: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 64: goto          114
 67: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
 70: ldc           #11  // String You used the special value forty-two
 72: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 75: goto          114
 78: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
 81: ldc           #12  // String You used the special value sixty-seven
 83: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
 86: goto          114
 89: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
 92: new           #13  // class java/lang/StringBuilder
 95: dup           
 96: invokespecial #14  // Method java/lang/StringBuilder."":()V
 99: ldc           #15  // String You used the a non-special value 
101: invokevirtual #16  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
104: iload_2       
105: invokevirtual #17  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
108: invokevirtual #18  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
111: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

Мы можем увидеть поиск таблицы в int в действии.

Итак, как вы это делаете со строками? Ну, один ответ - просто превратить switch в структуру if...else if...else. Но они сделали что-то более умное: они использовали хэш-код для оптимизации, а затем использовали equals для защиты от коллизий:

  switch (str) {
      case "abc":
          System.out.println("You used the special value 'abc'");
          break;
      case "def":
          System.out.println("You used the special value 'def'");
          break;
      case "ghi":
          System.out.println("You used the special value 'ghi'");
          break;
      default:
          System.out.println("You used the a non-special value '" + str + "'");
          break;
  }

становится:

124: aload         4
126: invokevirtual #19  // Method java/lang/String.hashCode:()I
129: lookupswitch  { // 3
            96354: 164
            99333: 180
           102312: 196
          default: 209
     }
164: aload         4
166: ldc           #20  // String abc
168: invokevirtual #21  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
171: ifeq          209
174: iconst_0      
175: istore        5
177: goto          209
180: aload         4
182: ldc           #22  // String def
184: invokevirtual #21  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
187: ifeq          209
190: iconst_1      
191: istore        5
193: goto          209
196: aload         4
198: ldc           #23  // String ghi
200: invokevirtual #21  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
203: ifeq          209
206: iconst_2      
207: istore        5
209: iload         5
211: tableswitch   { // 0 to 2
                0: 236
                1: 247
                2: 258
          default: 269
     }
236: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
239: ldc           #24  // String You used the special value 'abc'
241: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
244: goto          299
247: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
250: ldc           #25  // String You used the special value 'def'
252: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
255: goto          299
258: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
261: ldc           #26  // String You used the special value 'ghi'
263: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
266: goto          299
269: getstatic     #8   // Field java/lang/System.out:Ljava/io/PrintStream;
272: new           #13  // class java/lang/StringBuilder
275: dup           
276: invokespecial #14  // Method java/lang/StringBuilder."":()V
279: ldc           #27  // String You used the a non-special value '
281: invokevirtual #16  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
284: aload_3       
285: invokevirtual #16  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
288: ldc           #28  // String '
290: invokevirtual #16  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
293: invokevirtual #18  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
296: invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

Посмотрите, что они там сделали? Это в основном два switches теперь: один, чтобы получить уникальный номер для каждого случая на основе хэш-кода (но дважды проверяя с помощью equals), а затем второй для отправки.

Ответ 2

Оператор switch JDK6 работал с char, байтом, int примитивными типами данных и перечислением. В JDK 7 они поняли, что java.lang.String также является константой и добавлен в список типов данных, поддерживаемых оператором switch.

Например, следующий код отлично работает в JDK7.

 public static void OpenSource(String language) 
{
 switch (language) {
 case "PERL":
   System.out.println("PERL");
   break;
 case "Python":
   System.out.println("Python");
   break;
 case "Ruby":
   System.out.println("Ruby");
   break;
 case "PHP":
   System.out.println("PHP");
   break;
  default:
   throw new IllegalArgumentException();
 }

}