final
在以下Java表达式中做了什么?
catch (final SomeExceptionType e)
答案 0 :(得分:31)
它基本上意味着:
将“SomeExceptionType”捕获到变量“e”中,并保证在处理异常时我们不会为“e”分配不同的异常。
大多数情况下这都是矫枉过正,好像我正在将一个异常捕获到一个临时变量名中(e只对异常处理块有效),我不必严格警告自己,不要相信自己分配相同变量名称的不同(可能已创建)异常。
也就是说,也许这个区块是由一群心胸不同的人严重维护的,而且只是想要非常确定e是原始捕获的例外。
----编辑回应评论----
我无法想到这样做的一个非常好的理由。由于“e”不是成员(静态或其他),因此编译后的类文件不会使用名称“e”。说明这一点的另一种方法是,当您输入JVM字节码的异常处理块时,该对象将不会被分配给JVM处理框架可访问的任何成员名称,它将被推送到Thread的内部处理堆栈中。当前框架。
即使两个线程可以访问同一个Object,每个线程都有自己的帧,因此编译器从一个帧的内部堆栈中删除“e”名称不能被另一个线程更改。
考虑到这一点,宣布“e”final的唯一好处是确保未来的编码人员在进入街区后不会意外设置“e”。也许它们意味着在多线程环境中使代码更加健壮,但临时变量(名称仅在块中有效的那些)在编译后没有名称,它们被推送到帧的堆栈。
这就是为什么
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和中介创建线程到线程的通信,而第一个代码块不能有任何线程间通信,因为没有中介。
答案 1 :(得分:11)
目前它意味着final
与任何局部变量非常相似,除了它总是“明确分配”。
在最近的JDK7版本中,a Project Coin language change允许它指示一定程度的隐式静态类型正在进行。单个catch
可以通过公共基类型捕获许多不同的已检查异常,并且重新抛出包含上下文仅具有catch或声明可以(静态地说)抛出try
内的异常。 (有关更好的解释,请参阅链接。)
答案 2 :(得分:5)
问题,“final
做了什么?”该问题的其他答案以及here,here和here均已提及。但是在 try-catch 块的上下文中,Java Language Specification (JLS) §4.12.4 states(强调我自己):
- 尝试资源声明(第14.20.3节)的资源和多捕获子句(第14.20节)的例外参数是隐式声明最终。
- uni-catch子句(§14.20)的异常参数可能实际上是最终的,而不是显式声明为final。这样的参数从不隐式声明为最终。
在多捕捉条款中:
将final
关键字添加到 multi-catch子句只是明确了variable
隐式最终的事实。通常,只要final
关键字传达了有助于使代码更易读/可维护的其他信息,请使用它。
在uni-catch条款中
另一方面, uni-catch子句中的异常参数是从不隐式最终。因此,将final
关键字用于 uni-catch子句会阻止类似以下内容的发生:
try {
throw new Exception();
catch (Exception e){
e = null;
e.printStackTrace(); //throws a NullPointerException
}
这个简单的例子显而易见。但是有两个案例可能不太明显,需要使用final
:
final
添加到异常变量将确保在编译时捕获重新分配,而非运行时 作为一般经验法则,请在 uni-catch子句中使用final
关键字 in the same way you would use the final
keyword for a method parameter:
JLS§4.12.4:声明变量final可以作为有用的文档,它的值不会改变,可以帮助避免编程错误。
答案 3 :(得分:2)
变量上的final
关键字表示该变量只能分配一次,并且由于此处的赋值是由编译器完成的,这意味着以后代码中的变量无法更改。
这是一个重要的属性,因为它对维护者来说意味着这个特定变量在任何地方都具有这个特定的值,并且没有必要跟踪它的变化。这被认为非常有用,以至于Eclipse中的“清理”操作允许在可能的情况下添加“最终”,并且我相信您所看到的是这种自动清理的结果 ,因为大多数人类程序员都会保持短暂的阻塞,所以不需要这样的指示。