
В предыдущей статье я написал про некоторые новшества в Java 7
(входящие в Project Coin) а именно:
- Бриллиантовый оператор (Improved type inference for generic instance creation diamond)
- Автоматически закрывающиеся ресурсы (try-with-resource).
Конечно, это очень приятные вещи, но больше всего я рад появлению Strings in switch!
Возможность использовать строки в switch люди ждут уже где-то около 16 лет.
Например, вот ссылка на запрос по добавлению такой фичи:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=1223179.

Лично мне очень приятно, что наконец-то такая возможность появилось. Примеры использования можно посмотреть на официальной страничке Oracle учебника по Java (уже обновленного) .
Пример из учебника:
// http://download.oracle.com/javase/tutorial/java/nutsandbolts/switch.html public static int getMonthNumber(String month) { int monthNumber = 0; if (month == null) { return monthNumber; } switch (month.toLowerCase()) { case "january": monthNumber = 1; break; case "february": monthNumber = 2; break; case "march": monthNumber = 3; break; case "april": monthNumber = 4; break; case "may": monthNumber = 5; break; case "june": monthNumber = 6; break; case "july": monthNumber = 7; break; case "august": monthNumber = 8; break; case "september": monthNumber = 9; break; case "october": monthNumber = 10; break; case "november": monthNumber = 11; break; case "december": monthNumber = 12; break; default: monthNumber = 0; break; } return monthNumber; }
Стоит сразу отметить в этом примере проверку на null. Дело в том, что если в switch нам попадет ссылка на null, то возникнет NullPointerException.
Для того, чтобы понять почему это происходит, нужно посмотреть в какой код преобразуется switch . На самом деле switch от строк преобразуется в 2 (два!) switch-а.
Например, возьмем такой код:
private static void switchCheck(String s) { switch (s) { case "a": System.out.println("a"); case "abcd": System.out.println("abcd"); case "abdE": System.out.println("abdE"); default: System.out.println("default"); } }
Чтобы не мучиться с javap, можно взять какой-нибудь старенький java decompiler (например JAD) и попробовать посмотреть, что получилось:
private static void switchCheck(String s) { String s1 = s; byte byte0 = -1; switch (s1.hashCode()) { case 97: if (s1.equals("a")) { byte0 = 0; } break; case 2987074: if (s1.equals("abdE")) { byte0 = 2; } else if (s1.equals("abcd")) { byte0 = 1; } break; } switch (byte0) { case 0: System.out.println("a"); case 1: System.out.println("abcd"); case 2: System.out.println("abdE"); default: System.out.println("default"); break; } }
В принципе алгоритм напоминает устройство обычных хэш-таблиц.
Первым делом, вычисляем хэш. Именно поэтому, если в switch нам попадет ссылка на null, то возникнет NullPointerException.
Затем, если есть коллизии (например у строки "abcd" и "abdE" одинаковый хэш-код), то используем следующий свободный номер.
Далее перескакиваем в новом switch-е на новый адрес. Получается довольно эффективный алгоритм, который будет работать лучше чем цепочка из if () {} else if () {} else {}.

