Несколько возвратов: какой из них задает окончательное возвращаемое значение?

С учетом этого кода:

String test() {
    try {
        return "1";
    } finally {
        return "2";
    }
}

Значения языка определяют возвращаемое значение вызова test()? Другими словами: всегда ли это одно и то же в каждой JVM?

В Sun JVM возвращаемое значение 2, но я хочу быть уверенным, что это не зависит от VM.

Ответ 1

Да, спецификация языка определяет, что результатом является "2". Если VM делает это по-другому, это не соответствует спецификации.

Большинство компиляторов будут жаловаться на это. Например, Eclipse будет заявлять, что возвращаемый блок никогда не будет выполнен, но это неправильно.

Это ужасно вредная практика писать такой код, никогда не делайте этого:)

Ответ 2

Да, спецификация языка Java очень понятна по этой проблеме (14.20.2):

Оператор try с блоком finally выполняется первым выполнением блока try. Тогда есть выбор:

  • Если выполнение блока try завершается нормально, [...]
  • Если выполнение блока try завершается внезапно из-за выброса значения V, [...]
  • Если выполнение блока try завершается внезапно по любой другой причине R, тогда выполняется блок finally. Тогда есть выбор:
    • Если окончательный блок завершается нормально, [...]
    • Если блок finally завершается внезапно для разума S, то оператор try внезапно завершается по причине S (и причина R отбрасывается).

Ответ 3

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

String test() {
    try {
        System.exit(0);
    } finally {
        return "2";
    }
}

В этом случае JVM остановится, не выполняя блок finally.

Итак, в вашем примере возвращаемое значение будет 2.

Ответ 4

Да, если вы вернете что-то из блока finally, он заменит все, что вы могли бы вернуть из блока try или catch.

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

Ответ 5

После прочтения байтового кода программы код выглядит следующим образом:

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

Для программы:

String test() {
        try {
            System.out.println("try");
            return "1";
        } finally {
            System.out.println("finally");
            return "2";
        }
    }

Он преобразуется в:

String test()
    {
        System.out.println("try");
        String s = "1"; //temporary variable 
        System.out.println("finally");
        return "2";
        Exception exception;
        exception;
        System.out.println("finally");
        return "2";
    }

И Для программы: с блоком catch:

String test() {

        try {
            System.out.println("try");
            return "1";
        } catch (RuntimeException e) {
            System.out.println("catch");
            return "2";
        } finally {
            System.out.println("finally");
            return "3";
        }
    }

Преобразует в:

String test()
    {
        System.out.println("try");
        String s = "1";
        System.out.println("finally");
        return "3";
        RuntimeException e;
        e;
        System.out.println("catch");
        String s1 = "2";
        System.out.println("finally");
        return "3";
        Exception exception;
        exception;
        System.out.println("finally");
        return "3";
    }

Примечание. Выполнено с использованием JDK 1.7 и декомпилировано с использованием Cavaj.

Ответ 6

Вы можете ссылаться на приведенную ниже ссылку. Надеюсь, он предоставит все детали:

http://www.programmerinterview.com/index.php/java-questions/will-finally-run-after-return/

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

Спасибо, Chethan