我在一些示例BlackBerry Java类中看到了一些代码:
try
{
// stuff that will throw an exception
}
catch(final Exception e)
{
// deal with it
}
我认为final
是为了表现。根据标题,因为很少(永远?)任何理由修改已被抛出的Exception
,它们应该始终是final
吗?
如果是这样,这不是编译器可以完成的事情吗?或者它是由编译器完成的,手动添加final
根本没有影响吗?
答案 0 :(得分:17)
The Java Language Specification 11.2.2在最终例外与非最终例外之间有所区别:
throw语句(第14.18节),其抛出的表达式具有静态类型E,并且不是最终或有效的最终异常参数,可以抛出E或抛出的表达式可以抛出的任何异常类。
[...]
抛出语句表达式是catch子句C的最终或有效最终异常参数的throw语句可以抛出异常类E iff:
- E是一个异常类,声明C的try语句的try块可以抛出;和
- E的赋值与C的任何可捕获异常类兼容;和
- E与赋值在同一个try语句中的C左侧的catch子句的任何可捕获异常类不兼容。
有趣的是,JLS 14.20也说:
在uni-catch子句中,如果一个未声明为final(隐式或显式)的异常参数在其作用域内从不作为赋值运算符的左侧操作数发生,则它被认为是有效的。
换句话说,如果您不重新分配catch语句的e
(如e = new SomeOtherException();
),则会隐式声明为final。
所以我只能得出结论,它没有什么区别,除非在catch块中修改了异常,我能想出的唯一例子是:
public void method1() throws IOException {
try {
throw new IOException();
} catch (Exception e) { // e is not modified in catch => implicitly final
throw e; //compiles OK
}
}
//it works because method1 is semantically equivalent to method2:
public void method2() throws IOException {
try {
throw new IOException();
} catch (final Exception e) {
throw e;
}
}
public void method3() throws IOException {
try {
throw new IOException("1");
} catch (Exception e) {
e = new IOException("2"); //e modified: not implicitly final any more
throw e; //does not compile
}
}
答案 1 :(得分:2)
我相信final
在可能使用它的代码太长而无法轻松阅读和理解时非常有用。例如我会在可能的情况下创建字段final
,以确保它们在构造函数中正确分配,而不是在类中的任何位置进行修改。
将final
用于catch子句不太可能有用,因为a)保证设置值b)使用它的代码应该很短,c)无论如何很难修改它。
然而,没有什么可以阻止你这样做。
答案 2 :(得分:0)
我不确定它是关于性能的,而是关于约定的更多信息。如果您正在使用Eclipse,请尝试设置一个格式化程序,在任何可能的地方添加final
关键字,并使用该格式化程序重新格式化您的源代码。
答案 3 :(得分:-1)
我怀疑final会真正给出任何性能上的好处,因为异常实例是block local(这是一个非常好的答案,解释它https://stackoverflow.com/a/306966/492561)。
所以它只是作为一个明确的标记,表示我不会修改。
有时您可能需要修改异常以将其丢回,可能会编辑消息以使其在更高级别更清晰。
基本上我会说这是一个偏好的问题,有些人可能会喜欢其他人可能没有。
答案 4 :(得分:-1)
我见过几个项目,其中未修改的所有内容都必须是最终的(例如参数,字段,本地变量等)。
在PMD代码分析器中还有一个相应的样式检查,它验证所有可能的内容都被声明为final
。