Java:catch的含义(最终的SomeException e)?

7rtdyuoh  于 2023-02-18  发布在  Java
关注(0)|答案(4)|浏览(130)

final在下面的Java表达式中做什么?

catch (final SomeExceptionType e)
6yt4nkrj

6yt4nkrj1#

它的基本意思是:
将"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作为中介创建了线程到线程的通信,而第一个代码块不能进行任何线程间通信,因为没有中介。

kb5ga3dv

kb5ga3dv2#

目前,它的含义与任何局部变量final几乎相同,只是它总是“明确赋值”。
在最近的JDK7构建中,a Project Coin language change允许它指示某种程度的隐式静态类型正在进行。单个catch可以通过一个公共基类捕获许多不同的检查异常,并使用仅捕获或声明那些可能(静态地说)在try中抛出的异常的封闭上下文重新抛出。(参见链接以获得更好的解释。)

pgccezyw

pgccezyw3#

这个问题,“final做什么?”在这个问题的其他答案中,以及herehere,和here中都有提到,但是在 try-catch 块的上下文中,Java语言规范(JLS)§4.12.4规定(强调我自己):

*try-with-resources语句(参见14.20.3节)的资源和multi-catch子句(参见14.20节)的异常参数都被隐式声明为final。
uni-catch子句(§14.20)的异常参数可以是final的,而不是显式声明为final的,这样的参数 * 从不隐式声明为final
在多catch子句中

final关键字添加到一个 *multi-catch子句 * 中,只会显式地表明variable是隐式final的事实。通常,只要final关键字传达了有助于提高代码可读性/可维护性的附加信息,就可以使用它。

在单向捕获子句中

另一方面,*uni-catch子句 * 中的exception参数是never隐式final。因此,在 *uni-catch子句 * 中使用final关键字可以防止以下情况发生:

try {
     throw new Exception();
catch (Exception e){
    e = null;
    e.printStackTrace(); //throws a NullPointerException
}

这个问题在这个简单的例子中很明显,但是有两种情况可能不那么明显,需要使用final
1.如果catch块更复杂,则可能会发生意外的重新分配(尽管如此,如果catch块很复杂,则可能会做错)。
1.防止代码维护期间出现问题。将final添加到异常变量将确保在编译时捕获重新分配,* 而不是在运行时捕获 *
作为一般经验法则,请在 *uni-catch子句 * in the same way you would use the final keyword for a method parameter中使用final关键字:
日本劳工标准§4.12.4:将变量声明为final可以作为有用的文档,说明其值不会更改,并有助于避免编程错误。

2ul0zpep

2ul0zpep4#

变量上的final关键字意味着变量只能被赋值一次,由于这里的赋值是由编译器完成的,这意味着变量不能在代码中稍后更改。
这是一个重要的属性,因为它意味着对于维护者来说,这个特定的变量在任何地方使用时都将具有这个特定的值,并且没有必要跟踪它在哪里更改。这被认为是非常有用的,以至于Eclipse中的“清理”操作允许在任何可能的地方添加“final”,并且我相信您所看到的是这样一个自动清理的 * 结果 *。因为大多数人类程序员将保持捕捉块较短,因此不需要这样的指示。

相关问题