Следующий код не компилируется с javac 1.8.0_144 и ecj:
private LongSupplier foo() {
long fileSize;
try {
fileSize = canThrow();
} catch (IOException e) {
fileSize = 42;
}
LongSupplier foo = () -> 1 + fileSize;
return foo;
}
Мне интересно, если это ошибка в компиляторе. Определение эффективного финала в JLS:
Некоторые переменные, которые не объявлены окончательными, вместо этого считаются фактически окончательными:
Локальная переменная, декларатор которой имеет инициализатор (§14.4.2), эффективно является final, если выполняются все следующие условия:
Он не объявлен окончательным.
Он никогда не встречается в левой части выражения присваивания (§15.26). (Обратите внимание, что декларатор локальной переменной, содержащий инициализатор
, не является выражением присваивания.)Он никогда не встречается в качестве операнда префиксного или постфиксного оператора увеличения или уменьшения (§15.14, §15.15).
Локальная переменная, в объявлении которой отсутствует инициализатор, является окончательной, если выполняются все следующие условия:
Он не объявлен окончательным.
Всякий раз, когда он встречается в левой части выражения присваивания, он определенно не присваивается и не присваивается определенно перед присваиванием; то есть он определенно не назначен и не определен определенно назначен после правой части выражения присваивания (§16 (Определенное присвоение)).
Он никогда не используется в качестве операнда префиксного или постфиксного оператора инкремента или декремента.
Метод, конструктор, лямбда-выражение или параметр исключения (§8.4.1, §8.8.1, §9.4, §15.27.1, §14.20) рассматриваются с целью
определения того, является ли он действительно окончательным, как локальная переменная
, декларатор которой имеет инициализатор.
Насколько я понимаю, в пункте 2 присваивания в блоке try/catch разрешены, потому что fileSize
определенно не присвоено до присваивания.
Я думаю, что аргументация, объясняющая отказ от кода, такова:
- fileSize определенно не назначен перед блоком try
- fileSize присваивается (определенно? Кажется, 16.1.8 не заботится об исключениях в присваивании) после fileSize = canThrow()
- fileSize назначается после блока try
- fileSize не является однозначно неназначенным перед блоком catch и, следовательно, не является однозначно неназначенным перед назначением в блоке catch.
- таким образом, пункт 2 пункта 4.12.4 здесь не применяется
Это правильно?
fileSize = 0
или иным образом. то есть он не будет компилироваться, если вы сделаете переменнуюfinal
- person Peter Lawrey   schedule 22.12.2017