Java Magic. Part 3: Finally

Every experienced java programmer should know that finally block always executed. But is it true?

It depends on our definition of program execution. But, generally speaking, yes.

Normal program execution

Aha, look at this, someone might retort:

try {
  System.exit(1);
} finally {
  System.out.println("I'm here, man");
}

You just said, finally block always executed?

Well. In that case no, because we speaking about normal flow of program execution. This is abnormal.

From the official tutorial

Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute.

Your counter question might be: If second line of that code always exectued?

System.out.println("Line 1");
System.out.println("Line 2");
System.out.println("Line 3");

Sure, because it's linear flow. Nothing can break...BANG...Electricity unavailable. Program stopped.

What about this? It's also abnormal program execution, and we can't guarantee anything for 100%. In fact, this is the same as System.exit(1) or reset button on your computer or whatever.

That's why, we are talking about normal program execution. Only normal.

I said yes? I meant no!

Perpetuum Mobile

Consider the following code:

try {
  while (true) {
    System.out.println("I print here some useful information");
  }
} finally {
  System.out.println("Let me run");
}

Will be the line "Let me run" printed? Maybe yes, if printing error to standard output appear. Almost always the answer is no.

In that case, there are no difference between simple statement and finally block. None of them will be executed, throw this example away.

Threads

What about threads? We know that execution flow controlled by threads and they can be interrupted.

Assume that we have thread that perform some work, and other thread kills first one right before finally block. Finally wasn't executed.

Assume that we have deadlock between two threads, right before finally line. The same thing.

From the same tutorial

...if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.

So, we can treat thread like a program, and make one effective rule:

Rule 1. Finally executes always, except the case where controlling program or thread was aborted.

Finally we return

Ok, now we know when finally is not executed. But do we know when finally is executed?

Consider the example:

int someFunc() {
  try {
    return 0;
  } finally {
    return 1;
  }
}

The result is obviously 1. Just because finally is always executed.

Consider, next example:

int someFunc() {
  try {
    throw new RuntimeException();
  } finally {
    return 1;
  }
}

The result is 1 again. And it's a problem. We just lose the exception. Such issue known as exception swallowing. It is very dangerous, because client's code expect either exception or some value, but it always get only value.

One more less imaginary example.

String deposit(int amount) throws DAOException {
  try {
    return dao.deposit(amount);
  } finally {
    return "OK";
  }
}

The logic behind finally is to have some default value, and our deposit method throws the DAOExceptionwhere client code is responsible for its handling. Unfortunately, perhaps compiler forces you to handle thisDAOException it never occurs. And string "OK" will be returned.

Rule 2. Never use return from finally block.

Instead of conclusion

A lot of programmers are aware about this common mistake. But some are not. Maybe these two simple rules give you a tiny light on coward finally.

转载于:https://my.oschina.net/u/1469495/blog/717827

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值