Почему в Java нет блочных деклараций переменных? - PullRequest
10 голосов
/ 26 сентября 2008

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

void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
}

Практически все блочные языки, которые я когда-либо использовал, поддерживали это, включая тривиальные маленькие языки, для которых я писал интерпретаторы и компиляторы в школе. Perl может сделать это, как и Scheme, и даже C. Даже PL / SQL поддерживает это!

Каково обоснование этого дизайнерского решения для Java?

Редактировать: как кто-то указал, у Java есть блок-область видимости. Как называется концепция, о которой я спрашиваю? Хотел бы я вспомнить больше из этих уроков языкового дизайна. :)

Ответы [ 6 ]

24 голосов
/ 26 сентября 2008

Ну, строго говоря, Java имеет декларации переменных в блоке; так что это ошибка:

void methodName() {
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
  System.out.println(i); // error
}

Поскольку 'i' не существует вне блока for.

Проблема в том, что Java не позволяет вам создавать переменную с тем же именем другой переменной, которая была объявлена ​​во внешнем блоке того же метода. Как говорили другие люди, предположительно, это было сделано для предотвращения ошибок, которые трудно идентифицировать.

19 голосов
/ 26 сентября 2008

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

Точно так же нередко случайно теневые переменные и изменение поведения программы. Бессознательное дублирование существующей переменной может изменить программу так же легко, как и затенение переменной, как я упоминал выше.

Есть такая небольшая польза от того, чтобы разрешить эту слежку, что они исключили ее как слишком опасную. Серьезно, просто вызовите новую переменную как-нибудь еще, и проблема исчезнет.

12 голосов
/ 26 сентября 2008

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

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

ETA: это также может быть связано с обработкой исключений в Java. я думал, что часть этого вопроса была обсуждена в вопросе, связанном с тем, почему переменные, объявленные в разделе try, не были доступны в областях catch / finally.

10 голосов
/ 26 сентября 2008

Это приводит к ошибкам, которые трудно обнаружить, я думаю. Это похоже на C #.

Паскаль не поддерживает это, так как вы должны объявлять переменные над телом функции.

1 голос
/ 26 сентября 2008

Основное предположение в этом вопросе неверно.

Java имеет область действия уровня блока. Но он также имеет иерархию области видимости, поэтому вы можете ссылаться на i внутри цикла for, но не на j вне цикла for.

public void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    i = j * 2;
  }

  //this would cause a compilation error!
  j++;
}

Я не могу на всю жизнь понять, почему вы хотели бы, чтобы сферинг вел себя как-то иначе. Было бы невозможно определить, на какой i вы ссылались внутри цикла for, и я бы поспорил, что в 99,999% случаев вы хотите сослаться на i внутри метода.

0 голосов
/ 13 мая 2016

другая причина: если бы такой вид объявления переменных был разрешен, люди хотели бы (нужен?) Способ доступа к переменным внешнего блока. может быть добавлено что-то вроде «внешнего» ключевого слова:

void methodName() {
    int i = 7;
    for (int j = 0; j < 10; j++) {
        int i = outer.i * 2;
        if(i > 10) {
            int i = outer.outer.i * 2 + outer.i;
        }
    }
}
...