Java 7. Строки в переключателе



В предыдущей статье я написал про некоторые новшества в 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 {}.

Любое использование либо копирование материалов или подборки материалов сайта, элементов дизайна и оформления допускается лишь с разрешения правообладателя и только со ссылкой на источник: programador.ru

Телеграм канал: @prgrmdr
Почта для связи: vit [at] programmisty.com