20

我在一些示例 BlackBerry Java 类中看到了如下代码:

try
{
    // stuff that will throw an exception
}
catch(final Exception e)
{
    // deal with it
}

我认为这final是为了性能。根据标题,由于很少(曾经?)有任何理由修改Exception已经被抛出的,他们应该总是这样final吗?

如果是这样,这不是编译器可以完成的事情吗?还是由编译器完成并且final手动添加完全没有影响?

4

5 回答 5

17

Java 语言规范 11.2.2对最终异常和非最终异常进行了区分:

一个 throw 语句(第 14.18 节),其抛出的表达式具有静态类型 E,并且不是 final 或有效的 final 异常参数,可以抛出 E 或抛出的表达式可以抛出的任何异常类。
[...]
抛出的表达式是 catch 子句 C 的最终或有效最终异常参数的 throw 语句可以抛出异常类 E iff:

  • E是声明C的try语句的try块可以抛出的异常类;和
  • E 是与 C 的任何可捕获异常类兼容的赋值;和
  • E 与在同一 try 语句中声明在 C 左侧的 catch 子句的任何可捕获异常类的赋值都不兼容。

有趣的是,JLS 14.20还说:

在 uni-catch 子句中,未声明为 final(隐式或显式)的异常参数如果从未作为赋值运算符的左侧操作数出现在其范围内,则被认为是有效的 final。

换句话说,如果你不重新分配e你的 catch 语句(如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
    }
}
于 2012-08-21T09:27:20.707 回答
2

我相信final当可以使用它的代码太长而难以阅读和理解时很有用。例如,我会final在可能的情况下创建字段,以确保它们在构造函数中正确分配,并且不会在类中的任何地方进行修改。

使用finalcatch 子句不太可能有太大帮助,因为 a) 保证设置该值 b) 使用它的代码应该很短,c) 无论如何都很少修改它。

然而,没有什么能阻止你这样做。

于 2012-08-21T09:28:08.583 回答
0

我不确定这是关于性能,但更多的是关于约定。如果您使用的是 Eclipse,请尝试设置一个final尽可能添加关键字的格式化程序,并使用该格式化程序重新格式化您的源代码。

于 2012-08-21T09:23:37.067 回答
-1

我怀疑 final 是否真的会给性能带来任何好处,因为异常实例是块本地的(这是一个非常好的答案,解释它https://stackoverflow.com/a/306966/492561)。

所以它只是作为一个明确的标记,表示我不会修改。

有时您可能需要修改异常以将其返回,可能需要编辑消息以使其在更高级别更清晰。

本质上,我会说这是一个偏好问题,有些人可能喜欢,有些人可能不喜欢。

于 2012-08-21T09:27:50.533 回答
-1

我见过几个项目,其中未修改的所有内容都必须是最终的(例如参数、字段、本地变量等)。

PMD代码分析器中还有一个对应的样式检查,它验证所有可能的东西都被声明为final.

于 2012-08-21T09:31:44.277 回答