Java:catch的意义(最终的SomeException e)?
final
在以下Java表达式中做了什么?
catch (final SomeExceptionType e)
它基本上意味着:
将“SomeExceptionType”捕获到变量“e”中,并保证在处理exception期间我们不会为“e”分配不同的exception。
大多数情况下这都是矫枉过正,好像我正在将一个exception捕获到一个临时变量名中(e只对exception处理块有效),我不必严格警告自己,不要相信自己指定一个不同的(可能已创建)相同变量名称的exception。
也就是说,也许这个区块是由一群心胸不同的人严重维护的,而且只是想要非常确定e是原始捕获的exception。
—-编辑回应评论—-
我无法想到这样做的一个非常好的理由。 由于“e”不是成员(静态或其他),因此编译后的类文件不会使用名称“e”。 说明这一点的另一种方法是,当您输入JVM字节码的exception处理块时,该对象将不会被分配给JVM处理框架可访问的任何成员名称,它将被推送到Thread的内部处理堆栈中。当前帧。
即使两个线程可以访问同一个Object,每个线程都有自己的帧,因此编译器从一个帧的内部堆栈中删除“e”名称不能被另一个线程更改。
考虑到这一点,宣布“e”final的唯一好处是确保未来的编码人员在进入街区后不会意外设置“e”。 也许它们意味着在multithreading环境中使代码更加健壮,但临时变量(名称仅在块中有效的那些变量)在编译后没有名称,它们被推送到帧的堆栈中。
这就是为什么
public int safe() { int x = 5; x = x + 5; return x; }
通常被认为是线程安全的,因为它这样做(伪字节码)
(In the thread's current frame) push 5 push 5 add integers return
虽然这不是线程安全的
int x = 5; public void unsafe() { x = 5; x = x + 5; return x; }
因为它做到了这一点
(in the thread's current frame) push "this" push 5 set member x push "this" get member x push 5 add integer set member x get member x return
后一个字节码显然交错两个线程使用成员x和中间件创建线程到线程的通信,而第一个代码块不能有任何线程间通信,因为没有中间件。
目前它意味着final
与任何局部变量大致相同,除了它总是“明确分配”。
在最近的JDK7版本中, 项目硬币语言更改允许它指示一定程度的隐式静态类型正在进行。 单个catch
可以通过公共基类型捕获许多不同的已检查exception,并且重新抛出包含上下文仅具有catch或声明可以(静态地说)在try
抛出的exception。 (有关更好的解释,请参阅链接。)
变量的final
关键字意味着该变量只能分配一次,并且由于此处的赋值由编译器完成,这意味着该变量以后不能在代码中更改。
这是一个重要的属性,因为它对维护者来说意味着这个特定的变量在它使用的任何地方都具有这个特定的值,并且没有必要跟踪它的变化。 这被认为非常有用,以至于Eclipse中的“清理”操作允许在可能的情况下添加“最终”,并且我相信您所看到的是这种自动清理的结果 ,因为大多数人类程序员会保留阻塞短,所以不需要这样的指示。
问题是“ finally
做了什么?” 在这个问题的其他答案中,以及此处 , 此处和此处都提到了这个问题。 但是在try-catch块的上下文中, Java语言规范(JLS)§4.12.4声明 (强调我自己):
- try-with-resources语句 (第14.20.3节) 的资源和multi-catch子句 ( 第 14.20节)的exception参数被隐式声明为final 。
- uni-catch子句 ( 第 14.20节)的exception参数可以是有效的最终参数,而不是显式声明为final。 这样的参数永远不会被隐式声明为final 。
在multi-catch子句中 :
将final
关键字添加到multi-catch子句只是明确了variable
隐式最终的事实。 通常,每当final
关键字传达有助于使代码更易读/可维护的其他信息时,请使用它。
在uni-catch条款中
另一方面, uni-catch子句中的exception参数从不隐式最终。 因此,对uni-catch子句使用final
关键字会阻止类似以下内容的发生:
try { throw new Exception(); catch (Exception e){ e = null; e.printStackTrace(); //throws a NullPointerException }
在这个简单的例子中,问题很明显。 但是两个案例可能不那么明显并且finally
要使用:
- 如果捕获块更复杂,则可能意外重新分配。 (虽然,如果捕获块很复杂,你可能做错了。)
- 防止代码维护期间引起的问题。 将
final
添加到exception变量将确保在编译时捕获重新分配, 而不是运行时
作为一般经验法则,在uni-catch子句 中使用final
关键字的方式与在方法参数中使用final
关键字的方式相同 :
JLS§4.12.4 :声明变量final可以作为有用的文档,它的值不会改变,可以帮助避免编程错误。