Особливості випадку Java для цього (які, ймовірно, дуже схожі на випадок C #), пов'язані з тим, як компілятор Java визначає, чи може метод повернутись.
Зокрема, правила полягають у тому, що метод із типом повернення не повинен бути в змозі нормально завершитись, а натомість завжди повинен різко завершуватися (різко тут, вказуючи через оператор повернення чи виняток) за JLS 8.4.7 .
Якщо метод оголосив тип повернення, тоді виникає помилка часу компіляції, якщо тіло методу може нормально завершитись. Іншими словами, метод з типом повернення повинен повертатися лише за допомогою оператора return, який забезпечує повернення значення; не дозволяється «скидати кінець свого тіла» .
Компілятор дивиться, чи можливе нормальне припинення на основі правил, визначених у JLS 14.21 Недоступні заяви, оскільки він також визначає правила для нормального завершення.
Зокрема, правила недосяжних операторів становлять особливий випадок лише для циклів, які мають визначений true
постійний вираз:
Оператор while може нормально завершити iff принаймні одне з наступного:
Оператор while доступний, а вираз умови - це не постійний вираз (§15.28) зі значенням true.
Існує заява про перерву, яка виходить з оператора while.
Отже, якщо while
оператор може завершитись нормально , тоді оператор return нижче цього необхідний, оскільки код вважається доступним, і будь-який while
цикл без заяви про перерву чи постійний true
вираз вважається здатним завершити нормально.
Ці правила означають , що ваше while
заяву з постійним істинним виразом і без break
ніколи не вважало за , щоб завершити нормально , і тому будь-який код під ним не разу не вважаються досяжними . Кінець методу знаходиться внизу циклу, і оскільки все, що знаходиться під циклом, недоступне, таким є і кінець методу, і, отже, метод не може нормально завершитись (на що шукає компілятор).
if
заяви, з іншого боку, не мають спеціального винятку щодо постійних виразів, які надаються циклам.
Порівняйте:
// I have a compiler error!
public boolean testReturn()
{
final boolean condition = true;
if (condition) return true;
}
З:
// I compile just fine!
public boolean testReturn()
{
final boolean condition = true;
while (condition)
{
return true;
}
}
Причина розрізнення є досить цікавою і пов’язана з прагненням дозволити прапори умовної компіляції, які не викликають помилок компілятора (від JLS):
Можна очікувати, що оператор if буде оброблятися таким чином:
Оператор if-then може нормально завершити iff принаймні одне з наступних дій:
Оператор if-then доступний, а вираз умовою не є постійним виразом, значення якого є істинним.
Тоді твердження може нормально завершитися.
Тоді-оператор є доступним, якщо вислів if-then є досяжним, а вираз умовою не є постійним виразом, значення якого помилкове.
Оператор if-then-else може завершитись нормально, якщо тоді-оператор може завершитися нормально, або оператор else може завершитись нормально.
Тоді-оператор є доступним, якщо вислів if-then-else є доступним, а вираз умовою не є постійним виразом, значення якого є хибним.
Оператор else є доступним, якщо вислів if-then-else є доступним, а вираз умовою не є постійним виразом, значення якого є істинним.
Цей підхід відповідав би поводженню з іншими структурами управління. Однак, щоб дозволити зручне використання оператора if для цілей "умовної компіляції", фактичні правила відрізняються.
Наприклад, наступне твердження призводить до помилки часу компіляції:
while (false) { x=3; }
тому що заява x=3;
недосяжна; але поверхово схожий випадок:
if (false) { x=3; }
не призводить до помилки часу компіляції. Оптимізуючий компілятор може усвідомити, що оператор x=3;
ніколи не буде виконуватися, і може вибрати, щоб опустити код для цього оператора з генерованого файлу класу, але цей вираз x=3;
не вважається "недоступним" у технічному сенсі, зазначеному тут.
Обґрунтуванням цього різного режиму є надання можливості програмістам визначати "змінні прапорця", такі як:
static final boolean DEBUG = false;
а потім написати код, такий як:
if (DEBUG) { x=3; }
Ідея полягає в тому, що слід мати можливість змінити значення DEBUG з false на true або з true на false, а потім правильно скласти код без інших змін у тексті програми.
Чому констатація умовного розриву призводить до помилки компілятора?
Як зазначено в правилах доступності циклу, цикл у той час може також нормально завершитися, якщо він містить заяву про доступність перерви. Оскільки правила досяжності НЕ давало нічого if
про в тому п не приймає умову з if
до уваги на всіх, такий умовне if
заяву , в тому становище, завжди вважаються досяжним.
Якщо break
досяжна, код після циклу ще раз вважається досяжним. Оскільки немає доступного коду, який призводить до різкого припинення після циклу, метод вважається таким, що може завершитись нормально, і тому компілятор відзначає це як помилку.