Говорят, что Java игнорирует лишние пробелы.Почему c = a ++ + ++ b не компилируется без пробелов? - PullRequest
0 голосов
/ 12 декабря 2018

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

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

int a = 2;
int b = 3;    
int c = a+++b;
int d = a+++++b;

В то время как первый оператор компилировался отлично, последний выдает исключение:

Исключение в потоке "main" java.lang.RuntimeException: некомпилируемый исходный код - непредвиденный тип.Обязательно: переменная.Найдено: значение.

Однако, когда я добавил пробелы: int d = a++ + ++b, оно скомпилировалось.Почему это так?Говорят, что Java все равно игнорирует лишние пробелы.(У меня есть Java 8 и Netbeans IDE 8.2, если это имеет значение.)

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

UPD.Чтобы ответить на комментарии о том, что «дополнительные» имеют значение, а не все пробелы: поскольку int c = a++ + b; и int c=a+++b; оба компилируются, можно сказать, по аналогии, что в int d = a ++ + ++b; пробелы также являются «дополнительными».

Ответы [ 4 ]

0 голосов
/ 12 декабря 2018

Анализатор будет использовать столько символов, сколько возможно :

  • a+++b анализируется как a, ++, +, b.
  • a+++++b анализируется какa, ++, ++, +, b

Первый является допустимым синтаксисом, а второй - нет.

0 голосов
/ 12 декабря 2018

Раздел спецификации языка Java 3.2 , «Лексические переводы», говорит (выделено мое):

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

  1. Перевод Unicode избегает [...]

  2. перевод [...] в поток входных символов и ограничители строки [...].

  3. переводпотока входных символов и ограничителей строки, полученных в результате шага 2, в последовательность элементов ввода (§3.5), которые после пробела (§3.6) и комментариев (§3.7) отбрасываются, составляют токенов (§3.5), которые являются терминальными символами синтаксической грамматики (§2.3).

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

Таким образом, пробельные символы отбрасываются, но после определения «последовательности входных элементов».Раздел 3.5, «Элементы ввода и токены», гласит:

Пробел (§3.6) и комментарии (§3.7) могут служить для разделения токенов, которые, если они находятся рядом, могут быть токенизированы другим способом. Например, символы ASCII - и = во входных данных могут образовывать маркер оператора - = (§3.12), только если нет пробелов или комментариев.

0 голосов
/ 12 декабря 2018

Ответ, который должен быть помечен как правильный, является ответом, который строго соответствует тому, что JLS говорит относительно приведенных вами примеров.Этот ответ несколько спекулятивен, но он начинается с наблюдения того, что происходит с int c:

int c = a+++b;

Это оценивается как:

int c = (a++) + b; // c == 6

Так что, похоже, компилятор назначаетпостфиксный оператор, который имеет очень высокий приоритет.Теперь в:

int d = a+++++b;

если мы попытаемся также сформировать постфиксные операторы, мы столкнемся с проблемами:

int d = (a++)++ + b;

Выше не скомпилируется, потому что мы не можем применить ++ к чему-либо, кроме примитива.Таким образом, это не удается во время компиляции.

Я вижу ответ @Daniel, который цитирует JLS как говорящий, что самый длинный перевод возможен на каждом шаге, что означает, что postfix будет предприниматься до добавления, потому чтопоследний длиннее.Это согласуется с тем, что, кажется, происходит с выражением d.

0 голосов
/ 12 декабря 2018

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

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

Добавление больше пробелов сверх минимума не меняет результат.

Таким образом, обе строки имеют одинаковый результат:

int d = a++ + ++b;
int d = a++     +     ++b;

Вместо этого рассмотрим следующий код:

int d = a +++ b;

Каково ваше намерение?

int d = a + ++b;

или

int d = a++ + b;

Также с человеческой точки зрения невозможно понять без лишних пробелов.

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

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


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

...