Home > Archives > Scala基础之try...catch...finally

Scala基础之try...catch...finally

Published on

不论是在Java还是在Scala中,try..catch块的finally都是做一些收尾处理的,比如资源关闭等。如果在finally语句中如果添加了返回语句,将会发生什么呢?

def getResult: Int = try {
    println("try执行了吗?"
    return 1
} finally {
    println("finally执行了吗?"
    return 3
}

运行之后,发现getResult的返回值是3,反编译后可以看到如下代码:

public int getResult() {
  try { 
    Predef..MODULE$.println("try 执行了吗?");
    return 3;
  } finally {
    Predef..MODULE$.println("finally 执行了吗?");
  } 
  return 3;
}

显然,finally中的代码已经改变了原来方法的执行流程。

try { b } catch e1 finally e2

在Scala中,b的类型是try表达式的期望类型, e1实际上是一个偏函数: scala.PartialFunction[scala.Throwable, pt], pt <: b, 而e2的类型则是Unit。

上例,finally中的return语句使控制流程又回到了try块中,同时会将finally中的’返回值’作为最终返回值。

下面针对不同情况下,try...catch...finally的执行进行解释(finally中的代码无论如何都会执行):

(1) 计算b的过程中没有异常

如果在计算表达式e1的过程中抛出异常,那么整个表达式会中止,并且抛出异常(e1表达式中包含的异常)

如果在计算表达式的e1的过程中没有抛出异常,那么b就是整个表达式的返回值

(2) 计算b的过程中有异常(e1中的表达式仍然会被计算)

如果e1的计算过程也抛出异常,那么表达式会中止并且e1过程中的异常被抛出

如果e1的计算过程中没有抛出异常,那么原来b中的异常会在e1计算完成之后再次抛出。

但就像前面提到的,如果在finally中添加返回语句,执行流程发生改变。最终结果则为返回的内容,看上去就好像异常没有被抛出。

def getResult: Int = try {
  throw new RuntimeException
} finally {
  return 3
}

所以,上面这段代码还是会返回3,通过字节码可以更清晰的了解原因。


  public int getResult()
  {
    // Byte code:
    //   0: new 12  java/lang/RuntimeException
    //   3: dup
    //   4: invokespecial 16  java/lang/RuntimeException:<init> ()V
    //   7: athrow
    //   8: astore_1
    //   9: iconst_3
    //   10: ireturn
    //
    // Exception table:
    //   from to  target  type
    //   0  8 8 finally
  }

参考

> JLS 14.17 Return语句

声明: 本文采用 BY-NC-SA 授权。转载请注明转自: Allen写字的地方