jon*_*ive 2281 java return try-catch-finally
考虑到这一点的代码,我可以绝对肯定的是,finally
块总是执行,不管something()
是什么?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("I don't know if this will get printed out");
}
Run Code Online (Sandbox Code Playgroud)
jod*_*ell 2565
是的,finally
将在执行try或catch代码块后调用.
唯一try
不会被调用的是:
catch
;finally
或System.exit()
块中达到无限循环(或其他一些不可中断的,非终止语句);Kev*_*vin 533
示例代码:
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int test() {
try {
return 0;
}
finally {
System.out.println("finally trumps return.");
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
finally trumps return.
0
Run Code Online (Sandbox Code Playgroud)
小智 375
此外,虽然这是不好的做法,但如果在finally块中有一个return语句,它将胜过常规块中的任何其他返回.也就是说,以下块将返回false:
try { return true; } finally { return false; }
Run Code Online (Sandbox Code Playgroud)
从finally块中抛出异常也是一样的.
pol*_*nts 253
这是Java语言规范中的官方文字.
14.20.2.执行try-finally和try-catch-finally
通过首先执行块来执行
try
具有finally
块的语句try
.然后有一个选择:
- 如果
try
块的执行正常完成,[...]- 如果
try
块的执行由于throw
值V而突然完成,[...]- 如果
try
由于任何其他原因R突然完成finally
块的执行,则执行该块.然后有一个选择:
- 如果finally块正常完成,则该
try
语句突然完成的原因[R .- 如果
finally
块因原因S而突然完成,则try
语句突然完成,原因为S(并且原因R被丢弃).
return
实际的规范明确指出:
Run Code Online (Sandbox Code Playgroud)ReturnStatement: return Expression(opt) ;
一个
return
语句,没有Expression
尝试将控制权转移给包含它的方法或构造函数的调用者.阿
return
与语句Expression
尝试将控制转移到包含它的方法的调用; 值的值Expression
成为方法调用的值.前面的描述说" 尝试转移控制 "而不仅仅是" 转移控制 ",因为如果
try
方法或构造函数中的任何语句的try
块包含该return
语句,那么finally
这些try
语句的任何子句将按顺序执行,最内层到最外层,在将控制权转移给方法或构造函数的调用者之前.突然完成一个finally
条款可以破坏由return
声明发起的控制权转移.
Eya*_*der 156
除了其他响应之外,重要的是要指出'finally'有权通过try..catch块覆盖任何异常/返回值.例如,以下代码返回12:
public static int getMonthsInYear() {
try {
return 10;
}
finally {
return 12;
}
}
Run Code Online (Sandbox Code Playgroud)
同样,以下方法不会抛出异常:
public static int getMonthsInYear() {
try {
throw new RuntimeException();
}
finally {
return 12;
}
}
Run Code Online (Sandbox Code Playgroud)
虽然以下方法确实抛出它:
public static int getMonthsInYear() {
try {
return 12;
}
finally {
throw new RuntimeException();
}
}
Run Code Online (Sandbox Code Playgroud)
小智 115
我尝试了上面的例子,略有修改 -
public static void main(final String[] args) {
System.out.println(test());
}
public static int test() {
int i = 0;
try {
i = 2;
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
}
}
Run Code Online (Sandbox Code Playgroud)
以上代码输出:
最后胜过回归.
2
这是因为当return i;
执行时i
具有值2.在此之后finally
执行块,其中12被分配i
,然后System.out
执行out.
执行finally
块后,try
块返回2,而不是返回12,因为不会再次执行此return语句.
如果您将调试在Eclipse这个代码,那么你会得到执行后一种感觉System.out
的finally
块中return
的语句try
块被再次执行.但这种情况并非如此.它只返回值2.
Woo*_*tty 106
这是凯文答案的详细说明.重要的是要知道要返回的表达式之前进行评估finally
,即使之后返回它也是如此.
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int printX() {
System.out.println("X");
return 0;
}
public static int test() {
try {
return printX();
}
finally {
System.out.println("finally trumps return... sort of");
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
X
finally trumps return... sort of
0
Run Code Online (Sandbox Code Playgroud)
Chr*_*per 54
这就是最终块的整体想法.它允许您确保进行清理,否则可能会因为您返回而被忽略,当然.
无论 try块中发生了什么,最终都会被调用(除非你打电话System.exit(int)
或Java虚拟机因其他原因而启动).
Gar*_*our 40
考虑这一点的合理方式是:
use*_*189 18
除非由于JVM崩溃或来自调用而导致程序异常终止,否则始终执行finally块System.exit(0)
.
最重要的是,从finally块中返回的任何值都将覆盖执行finally块之前返回的值,因此在使用try finally时要小心检查所有出口点.
Raj*_*adi 18
不,并不总是一个例外情况是// System.exit(0); 在finally块阻止最终执行之前.
class A {
public static void main(String args[]){
DataInputStream cin = new DataInputStream(System.in);
try{
int i=Integer.parseInt(cin.readLine());
}catch(ArithmeticException e){
}catch(Exception e){
System.exit(0);//Program terminates before executing finally block
}finally{
System.out.println("Won't be executed");
System.out.println("No error");
}
}
}
Run Code Online (Sandbox Code Playgroud)
Mot*_*tti 13
最后总是运行这一点,只是因为它在返回后出现在代码中并不意味着它是如何实现的.Java运行时有责任在退出try
块时运行此代码.
例如,如果您有以下内容:
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
Run Code Online (Sandbox Code Playgroud)
运行时将生成如下内容:
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
Run Code Online (Sandbox Code Playgroud)
如果抛出未捕获的异常,则finally
块将运行,异常将继续传播.
小智 11
这是因为您将i的值指定为12,但未将i的值返回给函数.正确的代码如下:
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
Run Code Online (Sandbox Code Playgroud)
Mee*_*eet 10
答案很简单YES.
INPUT:
try{
int divideByZeroException = 5 / 0;
} catch (Exception e){
System.out.println("catch");
return; // also tried with break; in switch-case, got same output
} finally {
System.out.println("finally");
}
Run Code Online (Sandbox Code Playgroud)
OUTPUT:
catch
finally
Run Code Online (Sandbox Code Playgroud)
是的,它会被调用.这就是拥有finally关键字的重点.如果跳出try/catch块可能只是跳过finally块,那么就像把System.out.println放在try/catch之外一样.
添加到@ vibhash的答案,因为没有其他答案解释在如下所示的可变对象的情况下会发生什么.
public static void main(String[] args) {
System.out.println(test().toString());
}
public static StringBuffer test() {
StringBuffer s = new StringBuffer();
try {
s.append("sb");
return s;
} finally {
s.append("updated ");
}
}
Run Code Online (Sandbox Code Playgroud)
会输出
Run Code Online (Sandbox Code Playgroud)sbupdated
考虑以下程序:
public class SomeTest {
private static StringBuilder sb = new StringBuilder();
public static void main(String args[]) {
System.out.println(someString());
System.out.println("---AGAIN---");
System.out.println(someString());
System.out.println("---PRINT THE RESULT---");
System.out.println(sb.toString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
Run Code Online (Sandbox Code Playgroud)
从Java 1.8.162开始,上面的代码块给出了以下输出:
-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz
Run Code Online (Sandbox Code Playgroud)
这意味着使用finally
释放对象是一个很好的做法,如下面的代码:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null; // Just an example, but you can close streams or DB connections this way.
}
}
Run Code Online (Sandbox Code Playgroud)
finally
块总是在返回x
(计算)值之前执行。
System.out.println("x value from foo() = " + foo());
...
int foo() {
int x = 2;
try {
return x++;
} finally {
System.out.println("x value in finally = " + x);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
最后的 x 值 = 3
x 来自 foo() 的值 = 2
小智 7
finally
将执行,这是肯定的.
finally
在以下情况下不会执行:
情况1 :
当你执行System.exit()
.
案例2:
当您的JVM /线程崩溃时.
案例3:
当您的执行在手动之间停止时.
小智 7
我对不同论坛上提供的所有答案感到非常困惑,并决定最终编码并查看。输出是:
即使 try 和 catch 块中有 return,finally 也会被执行。
try {
System.out.println("try");
return;
//int i =5/0;
//System.exit(0 ) ;
} catch (Exception e) {
System.out.println("catch");
return;
//int i =5/0;
//System.exit(0 ) ;
} finally {
System.out.println("Print me FINALLY");
}
Run Code Online (Sandbox Code Playgroud)
输出
尝试
最后打印我
System.exit(0)
上面代码中的 try 和 catch 块替换,并且由于任何原因在它之前发生异常。Java语言规范描述了try-catch-finally和try-catch块如何在14.20.2中工作.
在任何地方它都没有指定始终执行finally块.但是对于try-catch-finally和try-finally块完成的所有情况,它确实指定在完成之前最终必须执行.
try {
CODE inside the try block
}
finally {
FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).
Run Code Online (Sandbox Code Playgroud)
JLS不保证在CODE之后执行FIN.JLS保证如果执行CODE和NEXT,则FIN将始终在CODE之后和NEXT之前执行.
为什么JLS不保证在try块之后总是执行finally块?因为这是不可能的.在完成try块之后但在执行finally块之前,JVM很可能会被中止(终止,崩溃,断电).JLS无法避免这种情况.
因此,任何因其正常行为而依赖于最终块的软件都会在其尝试块完成后始终执行.
try块中的返回值与此问题无关.如果执行在try-catch-finally之后到达代码,则保证finally块在之前执行,有或没有在try块内返回.
如果抛出异常,finally 就会运行。如果没有抛出异常,finally 就会运行。如果捕获到异常,则finally运行。如果没有捕获异常,则finally运行。
唯一不运行的时间是 JVM 退出时。
我试过这个,它是单线程的.
class Test {
public static void main(String args[]) throws Exception {
Object obj = new Object();
try {
synchronized (obj) {
obj.wait();
System.out.println("after wait()");
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
Run Code Online (Sandbox Code Playgroud)
主线程将永远处于等待状态,因此最终永远不会被调用,
所以控制台输出不会打印字符串:after wait()
或finally
同意@Stephen C,上面的例子是第三个案例之一:https://stackoverflow.com/a/65049/2987755
在以下代码中添加更多此类无限循环可能性:
// import java.util.concurrent.Semaphore;
class Test {
public static void main(String[] args) {
try {
// Thread.sleep(Long.MAX_VALUE);
// Thread.currentThread().join();
// new Semaphore(0).acquire();
// while (true){}
System.out.println("after sleep join semaphore exit infinite while loop");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
Run Code Online (Sandbox Code Playgroud)
情况2:如果JVM首先崩溃
import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Test {
public static void main(String args[]) {
try {
unsafeMethod();
// Runtime.getRuntime().halt(123);
System.out.println("After Jvm Crash!");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);
}
}
Run Code Online (Sandbox Code Playgroud)
参考:你如何崩溃JVM?
情况6:如果最终块将由守护程序线程执行,并且所有其他非守护程序线程在最终被调用之前退出.
class Test {
public static void main(String args[]) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
printThreads("Daemon Thread printing");
// just to ensure this thread will live longer than main thread
Thread.sleep(10000);
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
};
Thread daemonThread = new Thread(runnable);
daemonThread.setDaemon(Boolean.TRUE);
daemonThread.setName("My Daemon Thread");
daemonThread.start();
printThreads("main Thread Printing");
}
private static synchronized void printThreads(String str) {
System.out.println(str);
int threadCount = 0;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
System.out.println("Thread :" + t + ":" + "state:" + t.getState());
++threadCount;
}
}
System.out.println("Thread count started by Main thread:" + threadCount);
System.out.println("-------------------------------------------------");
}
}
Run Code Online (Sandbox Code Playgroud)
输出:这不打印"finally",这意味着"守护程序线程"中的"finally块"没有执行
Run Code Online (Sandbox Code Playgroud)main Thread Printing Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED Thread :Thread[main,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:3 ------------------------------------------------- Daemon Thread printing Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:2 ------------------------------------------------- Process finished with exit code 0
小智 6
如果不处理异常,则在终止程序之前,JVM会执行finally块.只有当程序的正常执行失败意味着由于以下原因终止程序时才会执行它.
通过导致致命错误导致进程中止.
由于内存损坏导致程序终止.
通过调用System.exit()
如果程序进入无限循环.
是的,因为没有控制语句可以阻止finally
执行.
这是一个参考示例,其中将执行所有代码块:
| x | Current result | Code
|---|----------------|------ - - -
| | |
| | | public static int finallyTest() {
| 3 | | int x = 3;
| | | try {
| | | try {
| 4 | | x++;
| 4 | return 4 | return x;
| | | } finally {
| 3 | | x--;
| 3 | throw | throw new RuntimeException("Ahh!");
| | | }
| | | } catch (RuntimeException e) {
| 4 | return 4 | return ++x;
| | | } finally {
| 3 | | x--;
| | | }
| | | }
| | |
|---|----------------|------ - - -
| | Result: 4 |
Run Code Online (Sandbox Code Playgroud)
在下面的变体中,return x;
将跳过.结果仍然是4
:
public static int finallyTest() {
int x = 3;
try {
try {
x++;
if (true) throw new RuntimeException("Ahh!");
return x; // skipped
} finally {
x--;
}
} catch (RuntimeException e) {
return ++x;
} finally {
x--;
}
}
Run Code Online (Sandbox Code Playgroud)
当然,参考资料会追踪他们的状态.此示例返回一个引用value = 4
:
static class IntRef { public int value; }
public static IntRef finallyTest() {
IntRef x = new IntRef();
x.value = 3;
try {
return x;
} finally {
x.value++; // will be tracked even after return
}
}
Run Code Online (Sandbox Code Playgroud)
在几个独特的场景中返回之后将不会调用finally块:如果首先调用System.exit(),或者JVM崩溃.
让我试着用最简单的方式回答你的问题.
规则1:finally块总是运行(尽管有例外.但是让我们坚持一段时间.)
规则2:当控制离开try或catch块时finally块中的语句运行.控制的转移可以由于正常执行,执行break,continue,goto或return语句或者宣传例外.
如果返回语句具体(因为它的标题),控件必须离开调用方法,因此调用相应的try-finally结构的finally块.return语句在finally块之后执行.
如果finally块中还有一个return语句,它肯定会覆盖try块中挂起的一个,因为它清除了调用栈.
您可以在此处参考更好的解释:http://msdn.microsoft.com/en-us/ ....这个概念在所有高级语言中大致相同.
try
- catch
- finally
是使用异常处理案例的关键词.
正常的解释
try {
//code statements
//exception thrown here
//lines not reached if exception thrown
} catch (Exception e) {
//lines reached only when exception is thrown
} finally {
// always executed when the try block is exited
//independent of an exception thrown or not
}
Run Code Online (Sandbox Code Playgroud)
finally块阻止执行......
System.exit(0);
归档时间: |
|
查看次数: |
477004 次 |
最近记录: |