Сегодня был на собеседовании по 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.
Комментариев нет:
Отправить комментарий