Рубрики
Без рубрики

Вопросы для интервью по управлению потоком Java (+ Ответы)

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

Автор оригинала: baeldung.

1. введение

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

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

2. Вопросы

Q1. Опишите операторы if-then и if-then-else. Какие типы выражений можно использовать в качестве условий?

Оба оператора говорят нашей программе выполнять код внутри них только в том случае, если определенное условие имеет значение true . Однако оператор if-then-else предоставляет вторичный путь выполнения в случае, если предложение if принимает значение false :

if (age >= 21) {
    // ...
} else {
    // ...
}

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

Q2. Опишите оператор switch. Какие типы объектов можно использовать в предложении switch?

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

Каждый путь помечен case или default , оператор switch оценивает каждое выражение case для соответствия и выполняет все операторы, следующие за соответствующей меткой, до тех пор, пока не будет найден оператор break . Если он не может найти совпадение, вместо этого будет выполнен блок default :

switch (yearsOfJavaExperience) {
    case 0:
        System.out.println("Student");
        break;
    case 1:
        System.out.println("Junior");
        break;
    case 2:
        System.out.println("Middle");
        break;
    default:
        System.out.println("Senior");
}

Мы можем использовать byte , short , char , int , их обернутые версии, enum и String sas switch значения.

Q3. Что происходит, когда мы забываем поместить оператор break в предложение case коммутатора?

Оператор switch проваливается. Это означает, что он будет продолжать выполнение всех меток case до тех пор, пока не найдет оператор break , даже если эти метки не соответствуют значению выражения.

Вот пример, чтобы продемонстрировать это:

int operation = 2;
int number = 10;

switch (operation) {
    case 1:
        number = number + 10;
        break;
    case 2:
        number = number - 4;
    case 3:
        number = number / 3;
    case 4:
        number = number * 10;
        break;
}

После выполнения кода number содержит значение 20 вместо 6. Это может быть полезно в ситуациях, когда мы хотим связать одно и то же действие с несколькими случаями.

Q4. Когда Предпочтительнее использовать Переключатель Над оператором If-Then-Else и наоборот?

Оператор switch лучше подходит при тестировании одной переменной против многих отдельных значений или когда несколько значений будут выполнять один и тот же код:

switch (month) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        days = 31;
        break;
case 2:
    days = 28;
    break;
default:
    days = 30;
}

Оператор if-then-else предпочтительнее, когда нам нужно проверить диапазоны значений или несколько условий:

if (aPassword == null || aPassword.isEmpty()) {
    // empty password
} else if (aPassword.length() < 8 || aPassword.equals("12345678")) {
    // weak password
} else {
    // good password
}

Q5. Какие типы циклов поддерживает Java?

Java предлагает три различных типа циклов: for , while и do-while .

Цикл for предоставляет способ итерации по диапазону значений. Это наиболее полезно, когда мы заранее знаем, сколько раз задача будет повторена:

for (int i = 0; i < 10; i++) {
     // ...
}

Цикл while может выполнять блок операторов, когда определенное условие истинно :

while (iterator.hasNext()) {
    // ...
}

A do-while – это вариант оператора while , в котором оценка выражения boolean находится в нижней части цикла. Это гарантирует, что код будет выполнен по крайней мере один раз:

do {
    // ...
} while (choice != -1);

Q6. Что такое расширенный цикл for?

Является ли другой синтаксис оператора for , предназначенный для перебора всех элементов коллекции, массива, перечисления или любого объекта, реализующего интерфейс Iterable :

for (String aString : arrayOfStrings) {
    // ...
}

Q7. Как вы можете выйти из цикла?

Используя оператор break , мы можем немедленно завершить выполнение цикла:

for (int i = 0; ; i++) {
    if (i > 10) {
        break;
    }
}

Q8. В чем разница между немаркированным и помеченным оператором break?

Немаркированный оператор break завершает внутренний оператор switch , for , while или do-while , в то время как помеченный оператор break завершает выполнение внешнего оператора.

Давайте создадим пример, чтобы продемонстрировать это:

int[][] table = { { 1, 2, 3 }, { 25, 37, 49 }, { 55, 68, 93 } };
boolean found = false;
int loopCycles = 0;

outer: for (int[] rows : table) {
    for (int row : rows) {
        loopCycles++;
        if (row == 37) {
            found = true;
            break outer;
        }
    }
}

Когда число 37 найдено, помеченный оператор break завершает самый внешний цикл for , и больше циклы не выполняются. Таким образом, циклы цикла заканчиваются значением 5.

Однако немеченый break завершает только самый внутренний оператор, возвращая поток управления к самому внешнему для , который продолжает цикл до следующей строки в переменной таблицы , делая циклы циклами со значением 8.

Q9. В чем разница между немаркированным и помеченным оператором continue?

Немаркированный оператор continue переходит к концу текущей итерации в самом внутреннем цикле for , while или do-while , в то время как помеченный оператор continue переходит к внешнему циклу, отмеченному данной меткой.

Вот пример, который демонстрирует это:

int[][] table = { { 1, 15, 3 }, { 25, 15, 49 }, { 15, 68, 93 } };
int loopCycles = 0;

outer: for (int[] rows : table) {
    for (int row : rows) {
        loopCycles++;
        if (row == 15) {
            continue outer;
        }
    }
}

Рассуждения те же, что и в предыдущем вопросе. Помеченный оператор continue завершает самый внешний цикл for .

Это означает, что циклы loop заканчиваются со значением 5, в то время как немаркированная версия завершает только самый внутренний оператор, в результате чего циклы loopCycles заканчиваются значением 9.

Q10. Опишите поток выполнения внутри конструкции try-catch-finally.

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

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

Блок finally всегда выполняется независимо от того, было ли вызвано исключение или нет внутри тела блока try .

Q11. В каких ситуациях блок finally может не выполняться?

Когда JVM завершается во время выполнения блоков try или catch , например, путем вызова System.exit(), или когда выполняющийся поток прерывается или убивается, блок finally не выполняется.

Q12. Каков результат выполнения следующего кода?

public static int assignment() {
    int number = 1;
    try {
        number = 3;
        if (true) {
            throw new Exception("Test Exception");
        }
        number = 2;
    } catch (Exception ex) {
        return number;
    } finally {
        number = 4;
    }
    return number;
}

System.out.println(assignment());

Код выводит число 3. Несмотря на то, что блок finally всегда выполняется, это происходит только после выхода блока try .

В этом примере оператор return выполняется до завершения блока try-catch . Таким образом, присвоение number в блоке finally не имеет никакого эффекта, так как переменная уже возвращается в вызывающий код метода ssignment .

Q13. В каких ситуациях блок try-finally может использоваться, даже если исключения могут не создаваться?

Этот блок полезен, когда мы хотим убедиться, что случайно не обойдем очистку ресурсов, используемых в коде, столкнувшись с оператором break , continue или return :

HeavyProcess heavyProcess = new HeavyProcess();
try {
    // ...
    return heavyProcess.heavyTask();
} finally {
    heavyProcess.doCleanUp();
}

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

public void doDangerousTask(Task task) throws ComplicatedException {
    try {
        // ...
        task.gatherResources();
        if (task.isComplicated()) {
            throw new ComplicatedException("Too difficult");
        }
        // ...
    } finally {
        task.freeResources();
    }
}

Q14. Как работает try-with-resources?

Оператор try-with-resources объявляет и инициализирует один или несколько ресурсов перед выполнением блока try и автоматически закрывает их в конце оператора независимо от того, был ли блок завершен нормально или внезапно. В качестве ресурса можно использовать любой объект, реализующий Автоклавируемые или Закрываемые интерфейсы:

try (StringWriter writer = new StringWriter()) {
    writer.write("Hello world!");
}

3. Заключение

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

Удачи вам в вашем интервью.