Объявление и инициализация переменных в Java переключатели


у меня есть сумасшедший вопрос о Java-коммутаторах.

int key = 2;

switch (key) {
    case 1:
        int value = 1;
        break;
    case 2:
        value = 2;
        System.out.println(value);
        break;
    default:
        break;
}

Сценарий 1 - при key два это успешно напечатать значение как 2.
Сценарий 2 - Когда я собираюсь комментария value = 2 на case 2: Он кричит, говоря возможно, значение локальной переменной не было инициализировано.

вопросы :

Сценарий 1: Если поток выполнения не переходит в case 1: (при key = 2), то как он знает тип значение переменной как int?

Сценарий 2: если компилятор знает тип переменной value как int, то он должен был получить доступ к int value = 1; выражение case 1:.(Объявление и инициализация). Тогда почему это sqawrk, когда я собираюсь комментировать value = 2 на case 2:, говоря возможно, значение локальной переменной не было инициализировано.

4 86

4 ответа:

операторы Switch являются странными с точки зрения определения области, в основном. От раздел 6.3 JLS:

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

в вашем случае, case 2 в том же блок как case 1 и появляется после него, хотя case 1 никогда не будет выполнена... таким образом, локальная переменная находится в области видимости и доступна для писать несмотря на то, что вы логически никогда не" выполняете " декларацию. (Объявление на самом деле не является" исполняемым", хотя инициализация есть.)

если закомментировать value = 2; присваивание, компилятор все еще знает, на какую переменную вы ссылаетесь, но вы не пройдете через какой-либо путь выполнения, который присваивает ему значение, поэтому вы получаете ошибку как вы бы при попытке прочитать любую другую не-определенно-назначенную локальную переменную.

я настоятельно рекомендую вам не чтобы использовать локальные переменные, объявленные в других случаях-это приводит к очень запутанному коду, как вы видели. Когда я ввожу локальные переменные в операторы switch (что я стараюсь делать редко-случаи должны быть очень короткими, в идеале), я обычно предпочитаю вводить новую область:

case 1: {
    int value = 1;
    ...
    break;
}
case 2: {
    int value = 2;
    ...
    break;
}

Я считаю, что это яснее.

переменная была объявлена (как int), но не инициализирована (присвоено начальное значение). Подумайте о строку:

int value = 1;

как:

int value;
value = 1;

The int value часть сообщает компилятору во время компиляции, что у вас есть переменная с именем value, которая является int. Элемент value = 1 часть инициализирует его, но это происходит во время выполнения и не происходит вообще, если эта ветвь коммутатора не введена.

From http://www.coderanch.com/t/447381/java-programmer-SCJP/certification/variable-initialization-within-case-block

объявления обрабатываются во время компиляции и не зависят от поток выполнения кода. Так как value объявляется в местных объем блока переключателя, он годен к употреблению везде в том блоке от суть его декларации.

интеграция JEP 325: переключение выражений (предварительный просмотр) в сборках раннего доступа JDK-12. Есть определенные изменения, которые можно увидеть из Джон -

  1. Область Действия Локальной Переменной - локальные переменные в случаях коммутатора теперь могут быть локальными для самого случая вместо всего блока коммутатора. Пример (похожий на то, что Джон пытался синтаксически также) учитывая Day класс enum для дальнейшего объяснения :

    public enum Day {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }
    
    // some another method implementation
    Day day = Day.valueOf(scanner.next());
    switch (day) {
        case MONDAY,TUESDAY -> {
            var temp = "mon-tue";
            System.out.println(temp);
        }
        case WEDNESDAY,THURSDAY -> {
            var temp = Date.from(Instant.now()); // same variable name 'temp'
            System.out.println(temp);
        }
        default ->{
            var temp = 0.04; // different types as well (not mandatory ofcourse)
            System.out.println(temp);
        }
    }
    
  2. Переключатель Выражений - если цель состоит в том, чтобы присвоить значение переменной, а затем использовать его, один раз можно использовать выражения switch. например,

    private static void useSwitchExpression() {
        int key = 2;
        int value = switch (key) {
            case 1 ->  1;
            case 2 -> 2;
            default -> {break 0;}
        };
        System.out.println("value = " + value); // prints 'value = 2'
    }