Несколько операторов возврата без ошибки компилятора



это был вопрос для интервью:



public class Demo {

public static void main(String[] args) {
System.out.println(foo());
}

static String foo() {
try {
return "try ...";
} catch (Exception e) {
return "catch ...";
} finally {
return "finally ..."; //got as result
}
}
}


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



warning: [finally] finally clause cannot complete normally
683   8  

8 ответов:

это не дает ошибку компиляции, потому что это разрешено спецификацией языка Java. Однако он дает предупреждающее сообщение, потому что в том числе return заявление в finally блок-это обычно плохая идея.

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

аналогично a finally блок обычно не должен вызывать исключение. Вот почему в предупреждении говорится, что finally блок должен завершаться нормально, то есть без return или бросать исключение.

это описано в спецификации языка Java:

§14.17

резкое завершение a finally предложение может нарушить передачу контроль инициируемых return заявление.

§14.20.2

если исполнение try блок завершается нормально, затем finally блок выполняется, и тогда есть выбор:

  • если элемент finally блок завершается нормально, то try оператор обычно завершается.
  • если finally блок завершается резко по причине S, то try оператор завершается резко по причине С.

если исполнение try блок завершается резко по любой другой причине R, тогда finally блок выполняется, и тогда есть выбор:

  • если finally блок завершается нормально, то try оператор завершается резко по причине Р.
  • если finally блок завершается резко по причине S, то try оператор завершается резко по причине S (и причина R отбрасывается).

нет ошибки времени компиляции, так как только 1 и ровно 1 из return оператор фактически вернет элемент управления обратно в вызывающий код.

как объяснил @Hoopje,return внутри try или catch будет выполняться первым, их соответствующий оператор возврата также будет выполняться. Но непосредственно перед возвратом элемента управления обратно в вызывающий код, он будет выполнять finally блок. Так вот, это block и returns что-то, так что это возвращение переопределяет предыдущее.

это по существу то же самое, что и это:

public boolean someMethod(){
        if(1 == 1){
            return true;
        }
        return false;
}

это не даст ошибку компиляции, хотя это даст предупреждение. Компилятор будет выдавать ошибку только тогда, когда есть шанс нет выполняется оператор return.

Гениальный Вопрос.. Согласно моим знаниям, оператор возврата блока try and catch передается в finally, если вы добавили finally block в свой код. Вот как это работает.

в этом случае все строки кода выполняются и вы можете попробовать выполнить отладку. Все три блока я попробовал ниже кода.

public class Main {

    public static void main(String[] args) {
        System.out.println(foo());
    }
    static String foo() {
        try {
            throw new Exception();
        } catch (Exception e) {
            return "catch ...";
        } finally {
            return "finally ..."; //got as result
        }
    }
}

вы можете получить идею из ссылки ниже. несколько возвратов: какой из них устанавливает окончательное возвращаемое значение?

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

(для краткого ответа-прочитайте полужирные и курсивные части ответ)

поток выполнения согласно Java 8 docs. Он предоставляет вам подробную информацию. Вы можете сделать вывод о выполнении операторов return на основе следующего.

оператор try с блоком finally выполняется путем первого выполнения блока try.

тогда есть выбор:

• Если выполнение блока try завершается нормально, то блок finally есть выполнили, и тогда есть выбор:

– Если блок finally завершается нормально, то оператор try завершается обычно.

– Если блок finally завершается внезапно по причине S, то оператор try завершается резко по причине С.

• Если выполнение блока try завершается внезапно из-за броска значения V, тогда есть выбор:

- Если тип времени выполнения V является назначением, совместимым с уловимым исключение класс любого предложения catch оператора try, затем первый (самый левый) такой выбрано предложение catch. Значение V присваивается параметру выбранное предложение catch, и блок этого предложения catch выполняется.

тогда есть выбор:

" Если блок catch завершается нормально, то выполняется блок finally. Тогда есть выбор:

" Если блок finally завершается нормально, то оператор try завершает обычно.

" Если блок finally завершается внезапно по какой-либо причине, то попробуйте оператор завершается резко по той же причине.

"Если блок catch завершается внезапно по причине R, то блок finally выполняемый. Тогда есть выбор:

" Если блок finally завершается нормально, то оператор try завершается резко по причине Р.

"Если блок finally завершается резко по причине S, то попробуйте оператор завершается резко по причине S (и причина R отбрасывается).

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

тогда есть выбор:

" Если блок finally завершается нормально, то оператор try завершается резко из-за броска значения В.

" Если блок finally завершается внезапно по причине S, то оператор try завершается резко по причине S (и бросок значения V отбрасывается и забытый.)

• Если выполнение блока try завершается внезапно по любой другой причине R, то finally блок выполняется, и тогда есть выбор:

– Если блок finally завершается нормально, то оператор try завершается резко по причине Р.

– Если finally блок завершается резко по причине S, затем оператор try завершается резко по причине S (и причина R отбрасывается).

объяснение понятно в этой ссылке- документация

попробуй:

он будет печатать: 1, 2, 3 и деление на ноль исключение

public class Demo {
  public static void main(String[] args) {
    System.out.println(foo());
  }
  public static String print(int a){
    System.out.println(a);
    return String.valueOf(a/0);
  }
  static String foo() {
    try {
      return print(1);
    } catch (Exception e) {
      return print(2);
    } finally {
      return  print(3);
    }
  }
}

Comments

    Ничего не найдено.