Spec-Zone .ru
спецификации, руководства, описания, API
|
Содержание | Предыдущий | Следующий | Индекс | Спецификация языка Java Второй Выпуск |
ГЛАВА 14
Последовательностью выполнения программы управляют операторы, которые выполняются для их эффекта и не имеют значений.
Некоторые операторы содержат другие операторы как часть их структуры; такие другие операторы являются подоператорами оператора. Мы говорим, что оператор S сразу содержит оператор U, если нет никакого оператора T, отличающегося от S, и U так, что S содержит T, и T содержит U. Тем же самым способом некоторые операторы содержат выражения (§15) как часть их структуры.
Первый раздел этой главы обсуждает различие между нормальным и резким завершением операторов (§14.1). Большинство остающихся разделов объясняет различные виды операторов, описывая подробно и их нормальное поведение и любой специальный режим резкого завершения.
Блоки объясняются сначала (§14.2), сопровождаются объявлениями локального класса (§14.3) и операторы объявления локальной переменной (§14.4).
Затем грамматический маневр, который обходит знакомое "свисание else
"проблема (§14.5) объясняется.
Операторы, которые будут знакомы C и программистам на C++, являются пустым (§14.6), маркировал (§14.7), выражение (§14.8), if
(§14.9), switch
(§14.10), while
(§14.11), do
(§14.12), for
(§14.13), break
(§14.14), continue
(§14.15), и return
(§14.16) операторы.
В отличие от C и C++, язык программирования Java имеет нет goto
оператор. Однако, break
и continue
операторам позволяют упомянуть метки оператора.
Операторы языка программирования Java, которые не находятся на языке C, throw
(§14.17), synchronized
(§14.18), и try
(§14.19) операторы.
Последний раздел (§14.20) этой главы адресует требование что каждый оператор быть достижимым в определенном техническом смысле.
Если все шаги выполняются как описано без индикации относительно резкого завершения, оператор, как говорят, обычно завершается. Однако, определенные события могут препятствовать тому, чтобы оператор обычно завершался:
break
(§14.14), continue
(§14.15), и return
операторы (§14.16) вызывают передачу управления, которое может предотвратить нормальное завершение операторов, которые содержат их.
throw
(§14.17) оператор также приводит к исключению. Исключение вызывает передачу управления, которое может предотвратить нормальное завершение операторов. У резкого завершения всегда есть связанная причина, которая является одним из следующего:
break
без метки
break
с данной меткой
continue
без метки
continue
с данной меткой
return
без значения
return
с данным значением
throw
с данным значением, включая исключения, выданные виртуальной машиной Java throw
с данным значением (§14.17) или исключение на этапе выполнения или ошибка (§11, §15.6).Если оператор оценивает выражение, резкое завершение выражения всегда вызывает непосредственное резкое завершение оператора с той же самой причиной. Все последующие шаги в нормальном режиме выполнения не выполняются.
Если иначе не определено в этой главе, резкое завершение подоператора вызывает непосредственное резкое завершение оператора непосредственно с той же самой причиной, и все последующие шаги в нормальном режиме выполнения оператора не выполняются.
Если иначе не определено, оператор обычно завершается, если все выражения, которые он оценивает и все подоператоры, которые он выполняет полный обычно.
Block: { BlockStatementsopt } BlockStatements: BlockStatement BlockStatements BlockStatement BlockStatement: LocalVariableDeclarationStatement ClassDeclaration StatementБлок выполняется, выполняя каждый из операторов объявления локальной переменной и других операторов в порядке от сначала, чтобы продлиться (слева направо). Если все эти операторы блока, полные обычно, то блок обычно завершается. Если любой из этих операторов блока, полных резко по любой причине, то блок завершается резко по той же самой причине.
Контекст локального класса, объявленного в блоке, является остальной частью сразу блока включения, включая его собственное объявление класса.
Имя локального класса C не может быть повторно объявлено как локальный класс непосредственно метода включения, конструктора, или блока инициализатора в рамках C, или ошибка времени компиляции происходит. Однако, объявление локального класса может быть затенено (§6.3.1) где угодно в объявлении класса, вложенном в пределах контекста объявления локального класса. У локального класса нет канонического имени, и при этом у него нет полностью определенного имени.
Это - ошибка времени компиляции, если объявление локального класса содержит кого-либо из следующих модификаторов доступа: public
, protected
, private,
или static
.
Вот пример, который иллюстрирует несколько аспектов правил, данных выше:
Первый оператор метода foo создает экземпляр задействованного классаclass Global { class Cyclic {} void foo() { new Cyclic(); // create a Global.Cyclic class Cyclic extends Cyclic{}; // circular definition { class Local{}; { class Local{}; // compile-time error } class Local{}; // compile-time error class AnotherLocal { void bar() { class Local {}; // ok } } } class Local{}; // ok, not in scope of prior Local }
Global.Cyclic
вместо экземпляра локального класса Cyclic
, потому что объявление локального класса еще не находится в контексте.
Факт, что контекст локального класса охватывает свое собственное объявление (не только его тело) означает что определение локального класса Cyclic
является действительно циклическим, потому что это расширяет себя, а не Global.Cyclic
. Следовательно, объявление локального класса Cyclic
будет отклонен во время компиляции.
Так как имена локального класса не могут быть повторно объявлены в пределах того же самого метода (или конструктор или инициализатор, в зависимости от обстоятельств), вторые и третьи объявления Local
результат в ошибках времени компиляции. Однако, Local
может быть повторно объявлен в контексте другого, более глубоко вложен, класс такой как AnotherLocal
.
Четвертое и последнее объявление Local
является законным, так как это происходит вне контекста любого предшествующего объявления Local
.
LocalVariableDeclarationStatement: LocalVariableDeclaration ; LocalVariableDeclaration: finalopt Type VariableDeclaratorsСледующее повторяется от §8.3, чтобы сделать представление здесь более четким:
VariableDeclarators: VariableDeclarator VariableDeclarators , VariableDeclarator VariableDeclarator: VariableDeclaratorId VariableDeclaratorId = VariableInitializer VariableDeclaratorId: Identifier VariableDeclaratorId [ ] VariableInitializer: Expression ArrayInitializerКаждый оператор объявления локальной переменной сразу содержался блоком. Операторы объявления локальной переменной могут быть смешаны свободно с другими видами операторов в блоке.
Объявление локальной переменной может также появиться в заголовке a for
оператор (§14.13). В этом случае это выполняется тем же самым способом, как будто это была часть оператора объявления локальной переменной.
Если дополнительный финал ключевого слова появляется в начале оператора объявления, объявляемая переменная является заключительной переменной (§4.5.4).
Тип переменной обозначается Типом, который появляется в объявлении локальной переменной, сопровождаемом любыми парами скобки, которые следуют за Идентификатором в операторе объявления.
Таким образом, объявление локальной переменной:
эквивалентно серии объявлений:int a, b[], c[][];
Скобки позволяются в операторах объявления как намек на традицию C и C++. Общее правило, однако, также означает что объявление локальной переменной:int a; int[] b; int[][] c;
эквивалентно серии объявлений:float[][] f[][], g[][][], h[]; // Yechh!
Мы не рекомендуем такую "смешанную нотацию" для объявлений массива.float[][][][] f; float[][][][][] g; float[][][] h;
Локальная переменная типа float
всегда содержит значение, которое является элементом набора значений плавающего (§4.2.3); точно так же локальная переменная типа double
всегда содержит значение, которое является элементом двойного набора значений. Это не разрешается для локальной переменной типа float
чтобы содержать элемент набора значений "пускают в ход расширенную экспоненту", которая не является также элементом набора значений плавающего, ни для локальной переменной типа double
чтобы содержать элемент набора значений "удваивают расширенную экспоненту", которая не является также элементом двойного набора значений.
Имя локальной переменной v не может быть повторно объявлено как локальная переменная непосредственно метода включения, конструктора или блока инициализатора в рамках v, или ошибка времени компиляции происходит. Имя локальной переменной v не может быть повторно объявлено как параметр исключения пункта выгоды в операторе попытки непосредственно метода включения, конструктора или блока инициализатора в рамках v, или ошибка времени компиляции происходит. Однако, локальная переменная метода или блока инициализатора может быть затенена (§6.3.1) где угодно в объявлении класса, вложенном в рамках локальной переменной.
Локальная переменная не может быть отнесена в использование полностью определенного имени (§6.6), только простое имя.
вызывает ошибку времени компиляции потому что инициализацияclass Test { static int x; public static void main(String[] args) { int x = x; } }
x
в рамках объявления x
как локальная переменная, и локальная переменная x
еще не имеет значения и не может использоваться.Следующая программа действительно компилирует:
потому что локальная переменнаяclass Test { static int x; public static void main(String[] args) { int x = (x=2)*2; System.out.println(x); } }
x
определенно присваивается (§16) прежде, чем он будет использоваться. Это печатает:
который компилирует правильно и производит вывод:4 Here is another example:class Test { public static void main(String[] args) { System.out.print("2+1="); int two = 2, three = two + 1; System.out.println(three); } }
Инициализатор для2+1=3
three
может правильно обратиться к переменной two
объявленный в более раннем операторе объявления, и вызове метода в следующей строке может правильно обратиться к переменной three
объявленный ранее в блоке.
Контекст локальной переменной объявляется в a for
оператор является остальной частью for
оператор, включая его собственный инициализатор.
Если объявление идентификатора как локальная переменная того же самого метода, конструктора, или блока инициализатора появляется в рамках параметра или локальной переменной того же самого имени, ошибка времени компиляции происходит.
Таким образом следующий пример не компилирует:
Это ограничение помогает обнаружить некоторых иначе очень неясные ошибки. Подобное ограничение на затенение элементов локальными переменными было оценено непрактичное, потому что добавление элемента в суперклассе могло заставить подклассы должными быть переименовывать локальные переменные. Связанные соображения делают ограничения на затенение локальных переменных элементами вложенных классов, или на затенении локальных переменных локальными переменными объявленными в пределах вложенных классов непривлекательный также. Следовательно, следующий пример компилирует без ошибки:class Test { public static void main(String[] args) { int i; for (int i = 0; i < 10; i++) System.out.println(i); } }
С другой стороны локальные переменные с тем же самым именем могут быть объявлены в двух отдельных блоках илиclass Test { public static void main(String[] args) { int i; class Local { { for (int i = 0; i < 10; i++) System.out.println(i); } } new Local(); } }
for
операторы, ни один из которых не содержит другой. Таким образом:
компиляции без ошибки и, когда выполняющийся, производят вывод:class Test { public static void main(String[] args) { for (int i = 0; i < 10; i++) System.out.print(i + " "); for (int i = 10; i > 0; i--) System.out.print(i + " "); System.out.println(); } }
0 1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1
Например, ключевое слово this
может использоваться, чтобы получить доступ к затененному полю x
, использование формы this.x
. Действительно, эта идиома обычно появляется в конструкторах (§8.8):
В этом примере конструктор берет параметры, имеющие те же самые имена как поля, которые будут инициализированы. Это более просто чем необходимость изобрести различные имена для параметров и не также сбивает с толку в этом стилизованном контексте. Вообще, однако, это считают плохим стилем, чтобы иметь локальные переменные с теми же самыми именами как поля.class Pair { Object first, second; public Pair(Object first, Object second) { this.first = first; this.second = second; } }
Каждая инициализация (кроме первого) выполняется, только если оценка предыдущего выражения инициализации обычно завершается. Выполнение объявления локальной переменной обычно завершается, только если оценка последнего выражения инициализации обычно завершается; если объявление локальной переменной не содержит выражений инициализации, то выполнение его всегда обычно завершается.
Как в C и C++, if
оператор языка программирования Java страдает от так называемого "свисания else
проблема," иллюстрированная этим обманчиво отформатированным примером:
if (door.isOpen()) if (resident.isVisible()) resident.greet("Hello!"); else door.bell.ring(); // A "dangling else"Проблема - это оба внешнее
if
оператор и внутреннее if
оператор мог бы очевидно собственный else
пункт. В этом примере можно было бы предположить что программист, предназначенный else
пункт, чтобы принадлежать внешнему if
оператор. Язык программирования Java, как C и C++ и много языков программирования перед ними, произвольно устанавливает декретом что else
пункт принадлежит самому внутреннему if
которому это могло бы возможно принадлежать. Это правило получается следующей грамматикой:
Statement: StatementWithoutTrailingSubstatement LabeledStatement IfThenStatement IfThenElseStatement WhileStatement ForStatement StatementWithoutTrailingSubstatement: Block EmptyStatement ExpressionStatement SwitchStatement DoStatement BreakStatement ContinueStatement ReturnStatement SynchronizedStatement ThrowStatement TryStatement StatementNoShortIf: StatementWithoutTrailingSubstatement LabeledStatementNoShortIf IfThenElseStatementNoShortIf WhileStatementNoShortIf ForStatementNoShortIfСледующее повторяется от §14.9, чтобы сделать представление здесь более четким:
IfThenStatement: if ( Expression ) Statement IfThenElseStatement: if ( Expression ) StatementNoShortIf else Statement IfThenElseStatementNoShortIf: if ( Expression ) StatementNoShortIf else StatementNoShortIfОператоры таким образом грамматически делятся на две категории: те, которые могли бы закончиться в
if
оператор, который имеет нет else
пункт ("короткий if
оператор") и те, которые определенно не делают. Только операторы, которые определенно не заканчиваются в коротком if
оператор может появиться как непосредственный подоператор перед ключевым словом else
в if
оператор, который действительно имеет else
пункт.
Это простое правило предотвращает "свисание else
"проблема. Поведение при выполнении оператора с "нет короткий if
"ограничение идентично поведению при выполнении того же самого вида оператора без "нет короткий if
"ограничение; различие оттягивается просто, чтобы разрешить синтаксическую трудность.
EmptyStatement: ;Выполнение пустого оператора всегда обычно завершается.
LabeledStatement: Identifier : Statement LabeledStatementNoShortIf: Identifier : StatementNoShortIfИдентификатор, как объявляют, является меткой сразу содержавшего Оператора.
В отличие от C и C++, язык программирования Java имеет нет goto
оператор; метки оператора идентификатора используются с break
(§14.14) или continue
(§14.15) операторы, появляющиеся где угодно в пределах помеченного оператора.
Контекст метки, объявленной помеченным оператором, является оператором, сразу включенным помеченным оператором.
Позвольте l быть меткой, и позволять м. быть сразу методом включения, конструктором, инициализатором экземпляра или статическим инициализатором. Это - ошибка времени компиляции если l тени (§6.3.1) объявление другой метки, сразу включенной в м.
Нет никакого ограничения против использования того же самого идентификатора как метка и как имя пакета, класса, интерфейса, метода, поля, параметра, или локальной переменной. Использование идентификатора, чтобы маркировать оператор не затеняет (§6.3.2) пакет, класс, интерфейс, метод, поле, параметр, или локальную переменную с тем же самым именем. Использование идентификатора как класс, интерфейс, метод, поле, локальная переменная или как параметр обработчика исключений (§14.19) не затеняет метку оператора с тем же самым именем.
Помеченный оператор выполняется, выполняя сразу содержавший Оператор. Если оператор маркируется Идентификатором, и содержавший Оператор завершается резко из-за a break
с тем же самым Идентификатором тогда помеченный оператор обычно завершается. Во всех других случаях резкого завершения Оператора помеченный оператор завершается резко по той же самой причине.
ExpressionStatement: StatementExpression ; StatementExpression: Assignment PreIncrementExpression PreDecrementExpression PostIncrementExpression PostDecrementExpression MethodInvocation ClassInstanceCreationExpressionОператор выражения выполняется, оценивая выражение; если у выражения есть значение, значение отбрасывается. Выполнение оператора выражения обычно завершается, если и только если оценка выражения обычно завершается.
В отличие от C и C++, язык программирования Java позволяет только определенным формам выражений использоваться в качестве операторов выражения. Отметьте, что язык программирования Java не позволяет "бросок void
"-void
не тип так традиционный прием C записи оператора выражения, такого как:
не работает. С другой стороны язык позволяет все самые полезные виды выражений в операторах выражений, и он не требует, чтобы вызов метода, используемый в качестве оператора выражения вызвал a(void) ... ; // incorrect!
void
метод, таким образом, такой прием никогда не почти необходим. Если прием необходим, или оператор присваивания (§15.26) или оператор объявления локальной переменной (§14.4) может использоваться вместо этого.if
Операторif
оператор позволяет условное выполнение оператора или условный выбор двух операторов, выполняясь один или другой, но не оба.
IfThenStatement: if ( Expression ) Statement IfThenElseStatement: if ( Expression ) StatementNoShortIf else Statement IfThenElseStatementNoShortIf: if ( Expression ) StatementNoShortIf else StatementNoShortIfУ Выражения должен быть тип
boolean
, или ошибка времени компиляции происходит.if-then
Операторif
-then
оператор выполняется первой оценкой Выражения. Если оценка Выражения завершается резко по некоторым причинам, if
-then
оператор завершается резко по той же самой причине. Иначе, выполнение продолжается, делая выбор, основанный на получающемся значении:
true
, тогда содержавший Оператор выполняется; if
-then
оператор обычно завершается, если и только если выполнение Оператора обычно завершается.
false
, никакие дальнейшие меры не предпринимаются и if
-then
оператор обычно завершается. if-then-else
Операторif
-then
-else
оператор выполняется первой оценкой Выражения. Если оценка Выражения завершается резко по некоторым причинам, то if
-then
-else
оператор завершается резко по той же самой причине. Иначе, выполнение продолжается, делая выбор, основанный на получающемся значении:
true
, тогда первый содержавший Оператор (один перед else
ключевое слово), выполняется; if
-then
-else
оператор обычно завершается, если и только если выполнение того оператора обычно завершается.
false
, тогда второй содержавший Оператор (один после else
ключевое слово), выполняется; if
-then
-else
оператор обычно завершается, если и только если выполнение того оператора обычно завершается. switch
Операторswitch
оператор передает управление одному из нескольких операторов в зависимости от значения выражения.
SwitchStatement: switch ( Expression ) SwitchBlock SwitchBlock: { SwitchBlockStatementGroupsopt SwitchLabelsopt } SwitchBlockStatementGroups: SwitchBlockStatementGroup SwitchBlockStatementGroups SwitchBlockStatementGroup SwitchBlockStatementGroup: SwitchLabels BlockStatements SwitchLabels: SwitchLabel SwitchLabels SwitchLabel SwitchLabel: case ConstantExpression : default :Тип Выражения должен быть
char
, byte
, short
, или int
, или ошибка времени компиляции происходит.
Тело a switch
оператор известен как блок переключателя. Любой оператор, сразу содержавший блоком переключателя, может быть маркирован один или больше case
или default
метки. Эти метки, как говорят, связываются с switch
оператор, как значения константных выражений (§15.28) в case
метки.
Все следующее должно быть истиной, или ошибка времени компиляции закончится:
case
константное выражение связалось с a switch
оператор должен быть присваиваемым (§5.2) типу switch
Выражение.
case
константные выражения связались с a switch
у оператора может быть то же самое значение.
default
метка может быть связана с тем же самым switch
оператор. В C и C++ тело a switch
оператор может быть оператором и операторами с case
метки не должны сразу содержаться тем оператором. Рассмотрите простой цикл:
гдеfor (i = 0; i < n; ++i) foo();
n
как известно, положителен. Прием, известный как устройство Варёного пудинга, может использоваться в C или C++, чтобы развернуть цикл, но это не допустимый код в языке программирования Java:
К счастью, этот прием, кажется, не широко известен или не используется. Кроме того это менее необходимо в настоящее время; этот вид преобразования кода находится должным образом в области современных оптимизирующих компиляторов.int q = (n+7)/8; switch (n%8) { case 0: do { foo(); // Great C hack, Tom, case 7: foo(); // but it's not valid here. case 6: foo(); case 5: foo(); case 4: foo(); case 3: foo(); case 2: foo(); case 1 foo(); } while (--q >= 0); }
Когда switch
оператор выполняется, сначала Выражение оценивается. Если оценка Выражения завершается резко по некоторым причинам, switch
оператор завершается резко по той же самой причине. Иначе, выполнение продолжается, сравнивая значение Выражения с каждым case
постоянный. Затем есть выбор:
case
константы равны значению выражения, тогда мы говорим что case
соответствия, и все операторы после соответствия case
метка в блоке переключателя, если таковые вообще имеются, выполняется в последовательности. Если все эти операторы обычно завершаются, или если нет никаких операторов после соответствия case
метка, тогда все switch
оператор обычно завершается.
case
соответствия, но есть a default
метка, тогда все операторы после соответствия default
метка в блоке переключателя, если таковые вообще имеются, выполняется в последовательности. Если все эти операторы обычно завершаются, или если нет никаких операторов после default
метка, тогда все switch
оператор обычно завершается.
case
соответствия и есть нет default
метка, тогда никакие дальнейшие меры не предпринимаются и switch
оператор обычно завершается. switch
оператор завершается резко, он обрабатывается следующим образом:
break
без метки никакие дальнейшие меры не предпринимаются и switch
оператор обычно завершается.
switch
оператор завершается резко по той же самой причине. Случай резкого завершения из-за a break
с меткой обрабатывается общим правилом для помеченных операторов (§14.7).
содержит блок переключателя, в котором код для каждого случая проваливается в код для следующего случая. В результате печатные издания программы:class Toomany { static void howMany(int k) { switch (k) { case 1: System.out.print("one "); case 2: System.out.print("too "); case 3: System.out.println("many"); } } public static void main(String[] args) { howMany(3); howMany(2); howMany(1); } }
Если код не должен провалиться случай, чтобы случиться этим способом, тоmany too many one too many
break
операторы должны использоваться, как в этом примере:
Эта программа печатные издания:class Twomany { static void howMany(int k) { switch (k) { case 1: System.out.println("one"); break; // exit the switch case 2: System.out.println("two"); break; // exit the switch case 3: System.out.println("many"); break; // not needed, but good style } } public static void main(String[] args) { howMany(1); howMany(2); howMany(3); } }
one two many
while
оператор неоднократно выполняет Выражение и Оператор, пока значение Выражения не false
.
WhileStatement: while ( Expression ) Statement WhileStatementNoShortIf: while ( Expression ) StatementNoShortIfУ Выражения должен быть тип
boolean
, или ошибка времени компиляции происходит.
A while
оператор выполняется первой оценкой Выражения. Если оценка Выражения завершается резко по некоторым причинам, while
оператор завершается резко по той же самой причине. Иначе, выполнение продолжается, делая выбор, основанный на получающемся значении:
true
, тогда содержавший Оператор выполняется. Затем есть выбор: while
оператор выполняется снова, начинаясь, переоценивая Выражение.
false
, никакие дальнейшие меры не предпринимаются и while
оператор обычно завершается. false
в первый раз, когда это оценивается, тогда Оператор не выполняется.
break
без метки никакие дальнейшие меры не предпринимаются и while
оператор обычно завершается. continue
без метки, тогда все while
оператор выполняется снова.
continue
с меткой L тогда есть выбор: while
у оператора есть метка L, тогда все while
оператор выполняется снова.
while
у оператора нет метки L, while
оператор завершается резко из-за a continue
с меткой L. while
оператор завершается резко по той же самой причине. Отметьте что случай резкого завершения из-за a break
с меткой обрабатывается общим правилом для помеченных операторов (§14.7). do
оператор неоднократно выполняет Оператор и Выражение, пока значение Выражения не false
.
DoStatement: do Statement while ( Expression ) ;У Выражения должен быть тип
boolean
, или ошибка времени компиляции происходит.
A do
оператор выполняется первым выполнением Оператора. Затем есть выбор:
do
оператор завершается резко по той же самой причине. Иначе, есть выбор, основанный на получающемся значении: true
, тогда все do
оператор выполняется снова.
false
, никакие дальнейшие меры не предпринимаются и do
оператор обычно завершается. do
оператор всегда выполняет содержавший Оператор, по крайней мере, однажды.
break
без метки тогда никакие дальнейшие меры не предпринимаются и do
оператор обычно завершается.
continue
без метки тогда оценивается Выражение. Затем есть выбор, основанный на получающемся значении: true
, тогда все do
оператор выполняется снова.
false
, никакие дальнейшие меры не предпринимаются и do
оператор обычно завершается. continue
с меткой L тогда есть выбор: do
у оператора есть метка L, тогда Выражение оценивается. Затем есть выбор: true
, тогда все do
оператор выполняется снова.
false
, никакие дальнейшие меры не предпринимаются и do
оператор обычно завершается. do
у оператора нет метки L, do
оператор завершается резко из-за a continue
с меткой L. do
оператор завершается резко по той же самой причине. Случай резкого завершения из-за a break
с меткой обрабатывается общим правилом (§14.7). toHexString
метод класса Integer
:
Поскольку по крайней мере одна цифра должна быть сгенерирована,public static String toHexString(int i) { StringBuffer buf = new StringBuffer(8); do { buf.append(Character.forDigit(i & 0xF, 16)); i >>>= 4; } while (i != 0); return buf.reverse().toString(); }
do
оператор является соответствующей управляющей структурой.for
Операторfor
оператор выполняет некоторый код инициализации, затем неоднократно выполняет Выражение, Оператор, и некоторый код обновления, пока значение Выражения не false
.
ForStatement: for ( ForInitopt ; Expressionopt ; ForUpdateopt ) Statement ForStatementNoShortIf: for ( ForInitopt ; Expressionopt ; ForUpdateopt ) StatementNoShortIf ForInit: StatementExpressionList LocalVariableDeclaration ForUpdate: StatementExpressionList StatementExpressionList: StatementExpression StatementExpressionList , StatementExpressionУ Выражения должен быть тип
boolean
, или ошибка времени компиляции происходит.for
операторfor
оператор выполняется первым выполнением кода ForInit:
for
оператор завершается резко по той же самой причине; любые выражения оператора ForInit направо от того, который завершался резко, не оцениваются. for
оператор (§14.13) включает все следующее:
for
оператор
for
оператор
for
оператор завершается резко по той же самой причине.
for
итеративный шаг выполняется, следующим образом:
for
оператор завершается резко по той же самой причине. Иначе, есть тогда выбор, основанный на присутствии или отсутствии Выражения и получающегося значения, если Выражение присутствует: true
, тогда содержавший Оператор выполняется. Затем есть выбор: for
оператор завершается резко по той же самой причине; любые выражения оператора ForUpdate направо от того, который завершался резко, не оцениваются. Если часть ForUpdate не присутствует, никакие меры не предпринимаются.
for
итеративный шаг выполняется. false
, никакие дальнейшие меры не предпринимаются и for
оператор обычно завершается. false
в первый раз, когда это оценивается, тогда Оператор не выполняется.
Если Выражение не присутствует, то единственный путь a for
оператор может завершиться, обычно при помощи a break
оператор.
for
оператор
break
без метки никакие дальнейшие меры не предпринимаются и for
оператор обычно завершается.
continue
без метки тогда следующие два шага выполняются в последовательности: for
итеративный шаг выполняется. continue
с меткой L тогда есть выбор: for
у оператора есть метка L, тогда следующие два шага выполняются в последовательности: for
итеративный шаг выполняется. for
у оператора нет метки L, for
оператор завершается резко из-за a continue
с меткой L. for
оператор завершается резко по той же самой причине. Отметьте что случай резкого завершения из-за a break
с меткой обрабатывается общим правилом для помеченных операторов (§14.7). break
Оператор
BreakStatement: break Identifieropt ;A
break
оператор без метки пытается передать управление самому внутреннему включению switch
, while
, do
, или for
оператор сразу метода включения или блока инициализатора; этот оператор, который вызывают целью повреждения, тогда сразу обычно завершается.
Быть точным, a break
оператор без метки всегда завершается резко, причина, являющаяся a break
без метки. Если нет switch
, while
, do
, или for
оператор включает break
оператор, ошибка времени компиляции происходит.
A break
оператор с меткой пытается передать управление помеченному оператору включения (§14.7), у которого есть тот же самый Идентификатор как его метка; этот оператор, который вызывают целью повреждения, тогда сразу обычно завершается. В этом случае, break
предназначайтесь не должен быть a while
, do
, for
, или switch
оператор. Оператор завершения должен обратиться к метке в пределах сразу метода включения или блока инициализатора. Нет никаких нелокальных переходов.
Быть точным, a break
оператор с меткой всегда завершается резко, причина, являющаяся a break
с меткой. Если никакой помеченный оператор с Идентификатором как его метка не включает break
оператор, ошибка времени компиляции происходит.
Это может быть замечено, тогда, это a break
оператор всегда завершается резко.
Предыдущие описания говорят "попытки передать управление", а не только "управление передачами" потому что, если есть кто-либо try
операторы (§14.19) в пределах повреждения предназначаются чей try
блоки содержат break
оператор, тогда любой finally
пункты тех try
операторы выполняются, в порядке, самом внутреннем к наиболее удаленному, прежде, чем управление будет передано цели повреждения. Резкое завершение a finally
пункт может разрушить передачу управления, инициируемого a break
оператор.
В следующем примере математический график представляется массивом массивов. График состоит из ряда узлов и ряда краев; каждый край является стрелкой, которая указывает от некоторого узла до некоторого другого узла, или от узла до себя. В этом примере предполагается, что нет никаких избыточных краев; то есть, для любых двух узлов P и Q, где Q может быть тем же самым как P, есть самое большее один край от P до К. Ноудса, представляются целыми числами, и есть край от узла i к узлу edges[
я][
j]
для того, каждого я и j, для который ссылка массива edges[
я][
j]
не бросает IndexOutOfBoundsException
.
Задача метода loseEdges
, данный целые числа i и j, должен создать новый график, копируя данный график, но опуская край от узла i к узлу j, если таковые вообще имеются, и краю от узла j к узлу i, если любой:
Отметьте использование двух меток оператора,class Graph { int edges[][]; public Graph(int[][] edges) { this.edges = edges; } public Graph loseEdges(int i, int j) { int n = edges.length; int[][] newedges = new int[n][]; for (int k = 0; k < n; ++k) { edgelist: { int z; search: { if (k == i) { for (z = 0; z < edges[k].length; ++z) if (edges[k][z] == j) break search; } else if (k == j) { for (z = 0; z < edges[k].length; ++z) if (edges[k][z] == i) break search; } // No edge to be deleted; share this list. newedges[k] = edges[k]; break edgelist; } //search // Copy the list, omitting the edge at position z. int m = edges[k].length - 1; int ne[] = new int[m]; System.arraycopy(edges[k], 0, ne, 0, z); System.arraycopy(edges[k], z+1, ne, z, m-z); newedges[k] = ne; } //edgelist } return new Graph(newedges); } }
edgelist
и search
, и использование break
операторы. Это позволяет код, который копирует список, опуская один край, чтобы быть совместно использованным двумя отдельными тестами, тестом для края от узла i к узлу j, и тесту для края от узла j к узлу i.continue
Операторcontinue
оператор может произойти только в a while
, do
, или for
оператор; операторы этих трех видов вызывают операторами цикла. Управление передает к точке продолжения цикла оператора цикла.
ContinueStatement: continue Identifieropt ;A
continue
оператор без метки пытается передать управление самому внутреннему включению while
, do
, или for
оператор сразу метода включения или блока инициализатора; этот оператор, который вызывают продолжать целью, тогда сразу заканчивает текущую итерацию и начинает новый.
Быть точным, такой continue
оператор всегда завершается резко, причина, являющаяся a continue
без метки. Если нет while
, do
, или for
оператор сразу метода включения или блока инициализатора включает continue
оператор, ошибка времени компиляции происходит.
A continue
оператор с меткой пытается передать управление помеченному оператору включения (§14.7), у которого есть тот же самый Идентификатор как его метка; тот оператор, который вызывают продолжать целью, тогда сразу заканчивает текущую итерацию и начинает новый. Продолжать цель должна быть a while
, do
, или for
оператор или ошибка времени компиляции происходят. Продолжать оператор должен обратиться к метке в пределах сразу метода включения или блока инициализатора. Нет никаких нелокальных переходов.
Более точно, a continue
оператор с меткой всегда завершается резко, причина, являющаяся a continue
с меткой. Если никакой помеченный оператор с Идентификатором как его метка не содержит continue
оператор, ошибка времени компиляции происходит.
Это может быть замечено, тогда, это a continue
оператор всегда завершается резко.
См. описания while
оператор (§14.11), do
оператор (§14.12), и for
оператор (§14.13) для обсуждения обработки резкого завершения из-за continue
.
Предыдущие описания говорят "попытки передать управление", а не только "управление передачами" потому что, если есть кто-либо try
операторы (§14.19) в пределах продолжать цели, чей try
блоки содержат continue
оператор, тогда любой finally
пункты тех try
операторы выполняются, в порядке, самом внутреннем к наиболее удаленному, прежде, чем управление будет передано продолжать цели. Резкое завершение a finally
пункт может разрушить передачу управления, инициируемого a continue
оператор.
В Graph
пример в предыдущем разделе, одном из break
операторы используются, чтобы закончить выполнение всего тела наиболее удаленного for
цикл. Это break
может быть заменен a continue
если for
сам цикл маркируется:
Чтобы использовать, если также, в значительной степени вопрос стиля программирования.class Graph { . . . public Graph loseEdges(int i, int j) { int n = edges.length; int[][] newedges = new int[n][]; edgelists: for (int k = 0; k < n; ++k) { int z; search: { if (k == i) { . . . } else if (k == j) { . . . } newedges[k] = edges[k]; continue edgelists; } // search . . . } // edgelists return new Graph(newedges); } }
return
Операторreturn
оператор возвращает управление invoker метода (§8.4, §15.12) или конструктор (§8.8, §15.9).
ReturnStatement: return Expressionopt ;A
return
оператор без Выражения должен содержаться в теле метода, который объявляется, используя ключевое слово void
, не возвратить любое значение (§8.4), или в теле конструктора (§8.8). Ошибка времени компиляции происходит если a return
оператор появляется в пределах инициализатора экземпляра или статического инициализатора (§8.7). A return
оператор без Выражения пытается передать управление invoker метода или конструктора, который содержит это.
Быть точным, a return
оператор без Выражения всегда завершается резко, причина, являющаяся a return
без значения.
A return
оператор с Выражением должен содержаться в объявлении метода, которое, как объявляют, возвращает значение (§8.4), или ошибка времени компиляции происходит. Выражение должно обозначить переменную или значение некоторого типа T, или ошибка времени компиляции происходит. Тип T должен быть присваиваемым (§5.2) объявленному типу результата метода, или ошибка времени компиляции происходит.
A return
оператор с Выражением пытается передать управление invoker метода, который содержит это; значение Выражения становится значением вызова метода. Более точно, выполнение такого return
оператор сначала оценивает Выражение. Если оценка Выражения завершается резко по некоторым причинам, то return
оператор завершается резко по этой причине. Если оценка Выражения обычно завершается, производя значение V, то return
оператор завершается резко, причина, являющаяся a return
со значением V. Если выражение имеет тип float
и не строго FP (§15.4), тогда значение может быть элементом или набора значений плавающего или набора значений "расширенная экспонента плавающая" (§4.2.3). Если выражение имеет тип double
и не строго FP, тогда значение может быть элементом или двойного набора значений или набора значений "двойная расширенная экспонента".
Это может быть замечено, тогда, это a return
оператор всегда завершается резко.
Предыдущие описания говорят "попытки передать управление", а не только "управление передачами" потому что, если есть кто-либо try
операторы (§14.19) в пределах метода или конструктора, чей try
блоки содержат return
оператор, тогда любой finally
пункты тех try
операторы будут выполняться, в порядке, самом внутреннем к наиболее удаленному, прежде, чем управление будет передано invoker метода или конструктора. Резкое завершение a finally
пункт может разрушить передачу управления, инициируемого a return
оператор.
throw
Операторthrow
оператор заставляет исключение (§11) быть брошенным. Результатом является непосредственная передача управления (§11.3), который может выйти из многократных операторов и многократного конструктора, инициализатора экземпляра, статического инициализатора и полевых оценок инициализатора, и вызовов метода до a try
оператор (§14.19) находится, который ловит брошенное значение. Если не такой try
оператор находится, тогда выполнение потока (§17), который выполнился throw
завершается (§11.3) после вызова uncaughtException
метод для группы потока, которой принадлежит поток.
ThrowStatement: throw Expression ;Выражение в операторе броска должно обозначить переменную или значение ссылочного типа, который присваиваем (§5.2) типу
Throwable
, или ошибка времени компиляции происходит. Кроме того по крайней мере одно из следующих трех условий должно быть истиной, или ошибка времени компиляции происходит:
RuntimeException
или подкласс RuntimeException
.
Error
или подкласс Error
. throw
оператор содержится в try
блок a try
оператор (§14.19) и тип Выражения присваиваем (§5.2) типу параметра по крайней мере одного catch
пункт try
оператор. (В этом случае мы говорим, что брошенное значение поймано try
оператор.)
throw
оператор содержится в методе или объявлении конструктора, и тип Выражения присваиваем (§5.2) по крайней мере одному типу, перечисленному в throws
пункт (§8.4.4, §8.8.4) объявления. throw
оператор сначала оценивает Выражение. Если оценка Выражения завершается резко по некоторым причинам, то throw
завершается резко по этой причине. Если оценка Выражения обычно завершается, производя не -null
оцените V, тогда throw
оператор завершается резко, причина, являющаяся a throw
со значением V. Если оценка Выражения обычно завершается, производя a null
значение, затем экземпляр V' класса NullPointerException
создается и бросается вместо null
. throw
оператор тогда завершается резко, причина, являющаяся a throw
со значением V'.
Это может быть замечено, тогда, это a throw
оператор всегда завершается резко.
Если есть какое-либо включение try
операторы (§14.19), чей try
блоки содержат throw
оператор, тогда любой finally
пункты тех try
операторы выполняются, поскольку управление передается исходящее, пока брошенное значение не поймано. Отметьте что резкое завершение a finally
пункт может разрушить передачу управления, инициируемого a throw
оператор.
Если a throw
оператор содержится в объявлении метода, но его значение не поймано некоторыми try
оператор, который содержит это, тогда вызов метода, завершается резко из-за throw
.
Если a throw
оператор содержится в объявлении конструктора, но его значение не поймано некоторыми try
оператор, который содержит это, тогда выражение создания экземпляра класса, которое вызвало конструктора, завершится резко из-за throw
.
Если a throw
оператор содержится в статическом инициализаторе (§8.7), затем проверка времени компиляции гарантирует, что или ее значение всегда является исключением непроверенным или ее значением, всегда пойман некоторыми try
оператор, который содержит это. Если во время выполнения, несмотря на эту проверку, значение не поймано некоторыми try
оператор, который содержит throw
оператор, тогда значение повторно бросается, если это - экземпляр класса Error
или один из его подклассов; иначе, это обертывается в ExceptionInInitializerError
объект, который тогда бросается (§12.4.2).
Если a throw
оператор содержится в инициализаторе экземпляра (§8.6), затем проверка времени компиляции гарантирует, что или ее значение всегда является исключением непроверенным или ее значением, всегда пойман некоторым оператором попытки, который содержит это, или тип выданного исключения (или один из его суперклассов) происходит в пункте бросков каждого конструктора класса.
Условно, объявленный пользователем типами throwable, как должны обычно объявлять, подклассы класса Exception
, который является подклассом класса Throwable
(§11.5).
synchronized
Операторsynchronized
оператор получает блокировку взаимного исключения (§17.13) от имени выполняющегося потока, выполняет блок, затем выпускает блокировку. В то время как выполняющемуся потоку принадлежит блокировка, никакой другой поток не может получить блокировку.
SynchronizedStatement: synchronized ( Expression ) BlockТип Выражения должен быть ссылочным типом, или ошибка времени компиляции происходит.
A synchronized
оператор выполняется первой оценкой Выражения.
Если оценка Выражения завершается резко по некоторым причинам, то synchronized
оператор завершается резко по той же самой причине.
Иначе, если значение Выражения null
, a NullPointerException
бросается.
Иначе, позвольте не -null
значение Выражения быть V. Выполняющийся поток блокирует блокировку, связанную с V. Затем Блок выполняется. Если выполнение Блока обычно завершается, то блокировка разблокирована и synchronized
оператор обычно завершается. Если выполнение Блока завершается резко по какой-либо причине, то блокировка разблокирована и synchronized
оператор тогда завершается резко по той же самой причине.
Получение блокировки, связанной с объектом, не делает себя, препятствуют тому, чтобы другие потоки получили доступ к полям объекта или вызвали несинхронизируемые методы на объект. Другие потоки могут также использовать synchronized
методы или synchronized
оператор стандартным способом, чтобы достигнуть взаимного исключения.
Блокировки, полученные synchronized
операторы являются тем же самым как блокировками, которые получаются неявно synchronized
методы; см. §8.4.3.6. Единственный поток может содержать блокировку не раз.
печатные издания:class Test { public static void main(String[] args) { Test t = new Test(); synchronized(t) { synchronized(t) { System.out.println("made it!"); } } } }
Этот пример был бы мертвая блокировка, если единственному потоку не разрешили заблокировать блокировку не раз.made it!
try
операторtry
оператор выполняет блок. Если значение бросается и try
оператор имеет один или больше catch
пункты, которые могут поймать это, затем управляют, будет передан первому такой catch
пункт. Если try
у оператора есть a finally
пункт, тогда другой блок кода выполняется, независимо от того ли try
блок завершается обычно или резко, и независимо от того ли a catch
пункт является первым данным контролем.
TryStatement: try Block Catches try Block Catchesopt Finally Catches: CatchClause Catches CatchClause CatchClause: catch ( FormalParameter ) Block Finally: finally BlockСледующее повторяется от §8.4.1, чтобы сделать представление здесь более четким:
FormalParameter: finalopt Type VariableDeclaratorIdСледующее повторяется от §8.3, чтобы сделать представление здесь более четким:
VariableDeclaratorId: Identifier VariableDeclaratorId [ ]Блок сразу после ключевого слова
try
вызывается try
блок try
оператор. Блок сразу после ключевого слова finally
вызывается finally
блок try
оператор.
A try
оператор может иметь catch
пункты (также названный обработчиками исключений). A catch
у пункта должен быть точно один параметр (который вызывают параметром исключения); объявленный тип параметра исключения должен быть классом Throwable
или подкласс Throwable
, или ошибка времени компиляции происходит. Контекстом переменной параметра является Блок catch
пункт.
У параметра исключения пункта выгоды не должно быть того же самого имени как локальная переменная или параметр метода или блока инициализатора сразу включение пункта выгоды, или ошибка времени компиляции происходит.
Контекст параметра обработчика исключений, который объявляется в a catch
пункт a try
оператор (§14.19) является всем блоком, связанным с catch
.
В пределах Блока catch
пункт, имя параметра не может быть повторно объявлено как локальная переменная непосредственно метода включения или блока инициализатора, и при этом это не может быть повторно объявлено как параметр исключения пункта выгоды в операторе попытки непосредственно метода включения или блока инициализатора, или ошибка времени компиляции происходит. Однако, параметр исключения может быть затенен (§6.3.1) где угодно в объявлении класса, вложенном в пределах Блока пункта выгоды.
Это - ошибка времени компиляции, если параметр исключения, который объявляется финалом, присваивается в пределах тела пункта выгоды.
Параметры исключения не могут быть отнесены в использование полностью определенных имен (§6.6), только простыми именами.
Обработчики исключений рассматривают в слева направо порядке: самое раннее catch
пункт принимает исключение, получая как его фактический параметр брошенный объект исключения.
A finally
пункт гарантирует что finally
блок выполняется после try
блок и любой catch
блок, который мог бы быть выполнен, независимо от того как листы управления try
блок или catch
блок.
Обработка finally
блок довольно сложен, таким образом, два случая a try
оператор с и без a finally
блок описывается отдельно.
try
оператор без a finally
блок выполняется первым выполнением try
блок. Затем есть выбор:
try
блок обычно завершается, тогда никакие дальнейшие меры не предпринимаются и try
оператор обычно завершается.
try
блок завершается резко из-за a throw
из значения V, тогда есть выбор: catch
пункт try
оператор, тогда первое (крайнее левое) такой catch
пункт выбирается. Значение V присваивается параметру выбранного catch
пункт, и Блок этого catch
пункт выполняется. Если тот блок обычно завершается, то try
оператор обычно завершается; если тот блок завершается резко по любой причине, то try
оператор завершается резко по той же самой причине.
catch
пункт try
оператор, тогда try
оператор завершается резко из-за a throw
из значения V. try
блок завершается резко по любой другой причине, тогда try
оператор завершается резко по той же самой причине. В примере:
исключениеclass BlewIt extends Exception { BlewIt() { } BlewIt(String s) { super(s); } } class Test { static void blowUp() throws BlewIt { throw new BlewIt(); } public static void main(String[] args) { try { blowUp(); } catch (RuntimeException r) { System.out.println("RuntimeException:" + r); } catch (BlewIt b) { System.out.println("BlewIt"); } } }
BlewIt
бросается методом blowUp
. try
-catch
оператор в теле main
имеет два catch
пункты. Тип времени выполнения исключения BlewIt
который не присваиваем переменной типа RuntimeException
, но присваиваемо переменной типа BlewIt
, таким образом, вывод примера:
BlewIt
try
оператор с a finally
блок выполняется первым выполнением try
блок. Затем есть выбор:
try
блок обычно завершается, тогда finally
блок выполняется, и затем есть выбор: finally
блок обычно завершается, тогда try
оператор обычно завершается.
finally
блок завершается резко по причине S, тогда try
оператор завершается резко по причине S. try
блок завершается резко из-за a throw
из значения V, тогда есть выбор: catch
пункт try
оператор, тогда первое (крайнее левое) такой catch
пункт выбирается. Значение V присваивается параметру выбранного catch
пункт, и Блок этого catch
пункт выполняется. Затем есть выбор: catch
блок обычно завершается, тогда finally
блок выполняется. Затем есть выбор: finally
блок обычно завершается, тогда try
оператор обычно завершается.
finally
блок завершается резко по любой причине, тогда try
оператор завершается резко по той же самой причине. catch
блок завершается резко по причине R, тогда finally
блок выполняется. Затем есть выбор:
catch
пункт try
оператор, тогда finally
блок выполняется. Затем есть выбор:
try
блок завершается резко по любой другой причине R, тогда finally
блок выполняется. Затем есть выбор:
производит вывод:class BlewIt extends Exception { BlewIt() { } BlewIt(String s) { super(s); } } class Test { static void blowUp() throws BlewIt { throw new NullPointerException(); } public static void main(String[] args) { try { blowUp(); } catch (BlewIt b) { System.out.println("BlewIt"); } finally { System.out.println("Uncaught Exception"); } } }
Uncaught Exception java.lang.NullPointerException at Test.blowUp(Test.java:7) at Test.main(Test.java:11)
NullPointerException
(который является своего рода RuntimeException
) это бросается методом blowUp
не пойман try
оператор в main
, потому что a NullPointerException
не присваиваемо переменной типа BlewIt
. Это вызывает finally
пункт тот, чтобы выполнить, после который выполнение потока main
, то, который является единственным потоком тестовой программы, завершается из-за непойманного исключения, которое обычно приводит к печати имени исключения и простого следа.
Этот раздел посвящается точному объяснению "достижимого" слова. Идея состоит в том, что должен быть некоторый возможный путь выполнения с начала конструктора, метода, инициализатора экземпляра или статического инициализатора, который содержит оператор к оператору непосредственно. Анализ принимает во внимание структуру операторов. За исключением специального режима while
, do
, и for
операторы, у выражения условия которых есть постоянная величина true
, значения выражений не принимаются во внимание в анализе потоков.
Например, компилятор Java примет код:
даже при том, что значение{ int n = 5; while (n > 7) k = 2; }
n
известен во время компиляции, и в принципе можно быть известно во время компиляции что присвоение на k
никогда не может выполняться.Компилятор Java должен работать согласно правилам, размеченным в этом разделе.
Правила в этом разделе определяют два технических термина:
Определения здесь позволяют оператору обычно завершаться, только если это достижимо.
Чтобы сократить описание правил, общепринятое сокращение "эквивалентность" используется, чтобы означать "если и только если."
if
оператор, имеет ли это else
часть, обрабатывается необычным способом. Поэтому это обсуждается отдельно в конце этого раздела.
switch
оператор может обычно завершать эквивалентность, по крайней мере одно из следующего является истиной: default
метка.
break
оператор, который выходит switch
оператор. switch
оператор достижим.
switch
оператор достижим, и по крайней мере одно из следующего является истиной: case
или default
метка.
switch
блок и что предыдущий оператор может обычно завершаться. while
оператор может обычно завершать эквивалентность, по крайней мере одно из следующего является истиной:
while
оператор достижим, и выражение условия не является константным выражением, значение которого false
. do
оператор может обычно завершать эквивалентность, по крайней мере одно из следующего является истиной: true
.
do
оператор содержит достижимое continue
оператор без метки, и do
оператор сам внутренний while
, do
, или for
оператор, который содержит это continue
оператор, и выражение условия не являются константным выражением со значением true
.
do
оператор содержит достижимое continue
оператор с меткой L, и do
у оператора есть метка L, и выражение условия не является константным выражением со значением true
.
break
оператор, который выходит do
оператор. do
оператор достижим. for
оператор может обычно завершать эквивалентность, по крайней мере одно из следующего является истиной:
for
оператор достижим, и выражение условия не является константным выражением, значение которого false
. break
, continue
, return
, или throw
оператор не может обычно завершаться.
synchronized
оператор может обычно завершать эквивалентность, которую содержавший оператор может обычно завершать. Содержавший оператор является достижимой эквивалентностью synchronized
оператор достижим.
try
оператор может обычно завершаться, эквивалентность оба из следующего истина: try
блок может обычно завершаться или любой catch
блок может завершиться normally
.
try
у оператора есть a finally
блок, тогда finally
блок может обычно завершаться. try
блок является достижимой эквивалентностью try
оператор достижим.
catch
блок C является достижимой эквивалентностью оба из следующего, истина: throw
оператор в try
блок достижим и может выдать исключение, тип которого присваиваем параметру catch
пункт C. (Выражение считают достижимой эквивалентностью самым внутренним оператором, содержащим это, достижим.)
catch
блокируйте в try
оператор так, что тип параметра К является тем же самым как или подкласс типа параметра А. finally
блок присутствует, это - достижимая эквивалентность try
оператор достижим. Можно было бы ожидать if
оператор, который будет обработан следующим способом, но они не правила, что язык программирования Java фактически использует:if-then
оператор может обычно завершать эквивалентность, которая по крайней мере одно из следующего true
:
then
- оператор является достижимой эквивалентностью if
-then
оператор достижим, и выражение условия не является константным выражением, значение которого false
.
if
-then
-else
оператор может обычно завершать эквивалентность then
- оператор может обычно завершаться или else
- оператор может обычно завершаться. then
- оператор является достижимой эквивалентностью if
-then
-else
оператор достижим, и выражение условия не является константным выражением, значение которого false
. else
оператор является достижимой эквивалентностью if
-then
-else
оператор достижим, и выражение условия не является константным выражением, значение которого true
. Этот подход был бы непротиворечивым с обработкой других управляющих структур. Однако, чтобы позволить, если оператор, который будет использоваться удобно в целях "условной компиляции", фактические правила отличаются.
if
-then
оператор может обычно завершать эквивалентность, это достижимо. then
- оператор является достижимой эквивалентностью if
-then
оператор достижим.
if
-then
-else
оператор может обычно завершать эквивалентность then
- оператор может обычно завершаться или else
- оператор может обычно завершаться. then
- оператор является достижимой эквивалентностью if
-then
-else
оператор достижим. else
- оператор является достижимой эквивалентностью if
-then
-else
оператор достижим. Как пример, следующий оператор приводит к ошибке времени компиляции:
потому что операторwhile (false) { x=3; }
x=3;
не достижимо; но поверхностно подобный случай:
не приводит к ошибке времени компиляции. Оптимизирующий компилятор может понять что операторif (false) { x=3; }
x=3;
никогда не будет выполняться и может хотеть опускать код для того оператора от сгенерированного class
файл, но оператор x=3;
не расценивается как "недостижимый" в техническом смысле, определенном здесь.Объяснение для этой отличающейся обработки должно позволить программистам определять "переменные флага", такие как:
и затем запишите код, такой как:static final boolean DEBUG = false;
Идея состоит в том, что должно быть возможно изменить значениеif (DEBUG) { x=3; }
DEBUG
от false
к true
или от true
к false
и затем скомпилируйте код правильно без других изменений к тексту программы.
Эта возможность к "условно компиляции" оказывает значительное влияние на, и отношение к, совместимость на уровне двоичных кодов (§13). Если ряд классов, которые используют такую переменную "флага", компилируется, и условный код опускается, это не достаточно позже, чтобы распределить только новую версию класса или интерфейса, который содержит определение флага. Изменение к значению флага, поэтому, не двоичный файл, совместимый с существующими ранее двоичными файлами (§13.4.8). (Есть другие причины такой несовместимости также, такие как использование констант в case
метки в switch
операторы; см. §13.4.8.)
Содержание | Предыдущий | Следующий | Индекс | Спецификация языка Java Второй Выпуск |