Почему в Java нет объявлений переменных с блочной областью видимости?

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

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

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

В чем причина этого дизайнерского решения для Java?

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
10
0
4 662
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

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

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

Ответ принят как подходящий

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

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

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

Впервые я увидел это в разделе «Обработка исключений». Там я ничего об этом не думал; Я просто предположил, что реализация препятствовала этому по какой-то внутренней причине. Только когда я заметил, что это повлияло на простые блоки, я действительно начал задаваться вопросом «почему»?

skiphoppy 26.09.2008 23:31

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

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

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

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

JavadocMD 26.09.2008 23:12

Единственный раз, когда они мне нравятся, это аргументы конструктора, поэтому я могу сделать "this.foo = foo". Изменение имен ради конструкторов некрасиво, некрасиво, некрасиво. "фу "," фу", мля.

Derek Park 26.09.2008 23:22

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

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

Потому что «i» не существует вне блока for.

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

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

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 внутри метода.

Я хочу сослаться на i внутри метода. Вот как работают C, Perl и Scheme. Так почему же из-за этого невозможно определить, что я хочу?

skiphoppy 26.09.2008 23:32

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

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;
        }
    }
}

Другие вопросы по теме