Управляющие операторы

Вопрос 1

Что будет, если попытаться откомпилировать и запустить следующий код:

for (int i = 0; i < 10; i++);

а. Код откомпилируется и отработает без проблем.
б. Во время компиляции возникнет ошибка Uncompilable source code, так как выражение не является законченной инструкцией (not a statement).
в. Код откомпилируется, но выпадет в ошибку во время выполнения.

а. Код откомпилируется и отработает без проблем.

После закрывающей скобки конструкции for должны идти либо блок кода в фигурных скобках {}, либо законченная инструкция (statement). По иронии судьбы, пустая инструкция, состоящая из одной точки с запятой в Java считается законченной. В приведённом примере кода за закрывающей скобкой конструкции for как раз стоит точка с запятой.

Вопрос 2

Что будет, если попытаться откомпилировать и запустить следующий код:

public class TestSwitch {


final static Integer i = 0;


public static void main(String[] args) throws Exception {


int g = 0;


switch (g) {

case i: System.out.println("Hello");

}

}

}

а. Код откомпилируется и отработает без проблем.
б. Во время компиляции возникнет ошибка Uncompilable source code - Wrong expression type, так как переменная i не является константой времени компиляции.
в. Код откомпилируется, но выпадет в ошибку во время выполнения.

б. Во время компиляции возникнет ошибка Uncompilable source code - Wrong expression type, так как переменная i не является константой времени компиляции.

К выражению в скобках после switch и к выражению после case предъявляются очень разные требования. После case могут располагаться только константы времени компиляции, как они определены в спецификации.

Значения констант времени компиляции должны быть рассчитаны во время компиляции. Такое возможно только применительно к примитивам и строковым литералам. Рассчитать значение ссылочных типов во время компиляции принципиально невозможно, поскольку во время компиляции неизвестно, по какому адресу в хипе будет расположен объект.

Код выполнится, если поменять тип переменной на соответствующий примитив: final static int i = 0; Но на практике это не всегда возможно.

Вопрос 3

Что будет, если попытаться откомпилировать и запустить следующий код:

if (true)

if (true)

System.out.println("yes");

else

System.out.println("no");

а. Код откомпилируется и отработает без проблем.
б. Во время компиляции возникнет ошибка illegal start of expression, '{' expected, так как нижняя пара if-else является сложной конструкцией и поэтому после верхнего if компилятор ожидает фигурную скобку '{'.
в. Во время компиляции возникнет ошибка unreachable statement, так как выражение после else никогда не будет выполнено.
г. Код откомпилируется, но выпадет в ошибку во время выполнения.

а. Код откомпилируется и отработает без проблем.

Программа выведет на консоль "yes". Нижняя конструкция if-else является целостной единичной инструкцией. Так как после скобок оператора if может идти одна инструкция, которая и будет выполнена, если условие равно true, то в данном случае этой одной инструкцией окажется if-else, каким бы сложным внутри себя он ни оказался.

Несмотря на то, что очевидно, что инструкция System.out.println("no"); никогда не будет выполнена, чтобы это узнать, нужно провести проверку внутри скобок второго if. Компилятор этого никогда делать не будет, так как это означает начать исполнять программу, чего компилятор не делает. Поэтому хотя при чтении программы недостижимая инструкция очевидна, для компилятора этот код ошибок не содержит.

Вопрос 4

Что будет выведено на консоль, если запустить следующий код:

int cent = 100;

for (int i = cent, j = 0; j < 2; j++) {

System.out.println(i++);

}

а. 100 и 100
б. 100 и 101
в. 101 и 102

б. 100 и 101

Внутри конструкции управляющего оператора for часть int i = cent, j = 0 выполнится лишь единожды, сколько бы ни было итераций самого цикла. Поэтому присваивание int i = cent произойдёт лишь один раз и на первой итерации i окажется равной 100.

Внутри инструкции System.out.println(i++); поскольку ++ постфиксный, то сначала на консоль уйдёт 100, и лишь потом будет приращение.

К началу второй итерации i уже будет равна 101. Внутри цикла это значение будет выведено на консоль, после чего переменная снова будет инкрементирована, уже до 102. Но так как цикл закончится, 102 никогда не будет выведено.

Вопрос 5

Что будет выведено на консоль, если запустить следующий код:

public static void main(String[] args) {


OUTER: for (int i = 0; i < 3; i++) {

INNER: for (int j = 0; j < 3; j++) {

if (j == 1) break INNER;

System.out.print(j);

}

}

}

а. 000
б. 010101
в. 020202

а. 000

Поскольку в консоль выводится только j, следить нужно только за этой переменной.

Нет никаких сомнений, что при j == 0, ноль будет выводится в консоль. Вопрос только в том, как сработает break INNER, когда на второй итерации внутреннего цикла j == 1. Оператор break передаст управление за закрывающую скобку, которая соответствует той открывающей скобке, перед которой стоит метка INNER:

OUTER: for (int i = 0; i < 3; i++) {

INNER: for (int j = 0; j < 3; j++) {

if (j == 1) break INNER;

System.out.print(j);

} // break INNER передаст управление сюда

}

То есть за выделенную выше жирным закрывающую скобку. В этом месте начинается новая итерация внешнего цикла.

Таким образом вывод в консоль будет срабатывать только при j == 0, а значит сведётся к "000".