Страницы

Поиск по вопросам

воскресенье, 24 ноября 2019 г.

Обязательно ли использовать else?


Сегодня был на собеседовании по Java и завалился на операторе if.
Задача была в том, чтобы написать метод, который возвращает второе по величине числ
из входного массива. Завалился на операторе if при проверке данных. Моя реализация была такой:

public int getSecondMaxNumber(int[] numbers) {
    if (numbers == null || numbers.length < 2) {
        throw new IllegalArgumentException();
    }
    // далее логика получения второго макс. числа
}


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

public int getSecondMaxNumber(int[] numbers) {
    if (numbers == null || numbers.length < 2) {
        throw new IllegalArgumentException();
    }
    else {
        // именно здесь логика получения второго макс. числа
    }
}


Зачем весь остальной код писать в блоке else, если при генерировании исключения поток выполнения этого метода прервется?

Аналогично, как выяснилось, и в случае, когда вместо генерации исключения прост
указывается return. И вообще, после оператора if всегда должен быть else.

Насколько я понял из слов технического менеджера, в случае с else JVM выполняет неку
оптимизацию. Хотелось бы более подробнее узнать об этом моменте - что за оптимизация и где можно подробнее об этом почитать?
    


Ответы

Ответ 1



В дополнение к ответу @VladD: я скомпилировал следующий класс с помощью java 8: public class IfElse { public int getSecondMaxNumber1(int[] numbers) { if (numbers == null || numbers.length < 2) { throw new IllegalArgumentException(); } return numbers[1]; } public int getSecondMaxNumber2(int[] numbers) { if (numbers == null || numbers.length < 2) { throw new IllegalArgumentException(); } else { return numbers[1]; } } } Видно, что байткод методов абсолютно одинаковый: $ javap -c IfElse.class Compiled from "IfElse.java" public class IfElse { public IfElse(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public int getSecondMaxNumber1(int[]); Code: 0: aload_1 1: ifnull 10 4: aload_1 5: arraylength 6: iconst_2 7: if_icmpge 18 10: new #2 // class java/lang/IllegalArgumentException 13: dup 14: invokespecial #3 // Method java/lang/IllegalArgumentException."":()V 17: athrow 18: aload_1 19: iconst_1 20: iaload 21: ireturn public int getSecondMaxNumber2(int[]); Code: 0: aload_1 1: ifnull 10 4: aload_1 5: arraylength 6: iconst_2 7: if_icmpge 18 10: new #2 // class java/lang/IllegalArgumentException 13: dup 14: invokespecial #3 // Method java/lang/IllegalArgumentException."":()V 17: athrow 18: aload_1 19: iconst_1 20: iaload 21: ireturn }

Ответ 2



Нет, нигде нет никакого правила по поводу обязательного else. Наоборот, для конкретно вашего случая форма if без else лучше, так как не увеличивае без толку глубину вложенности, а акцентирует внимание на том, что код сначала проверяет параметры, и после этого выполняется как есть. В предложенном варианте с else код всего метода обладал бы добавочной глубиной вложенности из-за тривиальной проверки в начале. Даже если бы в недрах JVM была бы оптимизация, выполняющая код с else скорее, вс равно правильнее было бы писать не так, как оптимальнее (расход времени на условный оператор порядка наносекунды, так что много вы не выиграете), а как понятнее. Непродуманная оптимизация — причина всех бед. Устройтесь в нормальную компанию, в этой технические специалисты никуда не годятся. P. S.: Поскольку смысл кода что с else, что без одинаков, есть хорошие шансы, чт с подключенными оптимизациями java сгенерирует для обоих вариантов в точности одинаковый промежуточный код. Попробуйте! (У меня нет компилятора java под рукой.)

Ответ 3



Радуйтесь что туда не попали. К примеру в исходниках jdk никакого else нет. java.lang.Object#wait(long, int) из jdk 1.8 к примеру. public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { timeout++; } wait(timeout); }

Ответ 4



Мне кажется, это как-то связано с механизмом branch prediction. Предположим, ваша функция будет выполнена много-много раз. Очевидно, что код идущий в блоке else будет выполнен на порядок чаще чем тело блока if. И вот на основании этой информации могут быть выполнены некоторые оптимизации, врод заинлайнить вызовы методов в блоке else или заинлайнить весь ваш метод в вышестоящий цикл. Или проверка вообще выкинута. Но это только мои догадки. Возможно они что-то об этом слышали и пытались не к месту козырнуть своими знаниями. Да и вообще бред придираться к этому на собеседовании.

Ответ 5



В вашем примере это только делает лишние хлопоты, соображайте так public int getSecondMaxNumber(int[] numbers) { if (numbers == null || numbers.length < 2) { throw new IllegalArgumentException(); //если условие выполнится значит //вылетит исключение которое прервет эту функцию //а значит else тут будет лишним } // именно здесь логика получения второго макс. числа } Возьмем такой пример i = 1; if(i == 1){ //выполняем действие, но это действие не будет прерывать функцию } if(i == 2){ //получается джава будет сравнивать еще раз, не зависимо от того выполнилась ли i == 1 } //дабы джава не сравнивала еще раз обернем в else if(i == 1){ }else if(i == 2){ } В таких случаях используется else.

Комментариев нет:

Отправить комментарий