【问题标题】:Why use the "finally" keyword? [duplicate]为什么要使用“finally”关键字? [复制]
【发布时间】:2019-12-07 04:54:27
【问题描述】:

我了解“finally”关键字在各种语言中的用途,但是,我很难理解为什么您会在没有格式偏好的情况下使用它。

例如,在 PHP 中:

try {
  possibleErrorThrownFunction();
}
catch (CustomException $customException) {
  // handle custom error
}
catch (Exception $exception) {
  // handle the error
}
finally {
  // run this code every single time regardless of error or not
}

这段代码在做什么和这个有什么区别?

try {
  possibleErrorThrownFunction();
}
catch (CustomException $customException) {
  // handle custom error
}
catch (Exception $exception) {
  // handle the error
}

// run this code every single time regardless of error or not

由于错误被捕获,最后一行不是总是会运行吗?在这种情况下,除非您只想保持代码样式的格式,否则就没有真正使用finally 的情况?

如果我在这里遗漏了什么,finally 语句是必要的并且与仅在 try/catch 语句之后放置代码不同的示例将很有帮助。

【问题讨论】:

  • 无论是否抛出异常,最终都会总是被执行。这通常用于清理任务,例如解锁文件或编译器 (PHP) 不执行的操作。
  • 正如@MarkusZeller 所说,它通常用于清理。查看 Java 文档以获取详细信息:docs.oracle.com/javase/tutorial/essential/exceptions/…
  • @MarkusZeller php 被解释,而不是编译。
  • 如果你抛出一个未被任何 catch 子句处理的异常,或者如果你从任何处理程序中抛出一个异常,那么 catch 子句后面的代码将永远不会被执行,而finally 块将在异常进一步向下传播到调用堆栈之前执行
  • @bassxzero 是的,(PHP)代码被解释了,但最终它被编译成字节码。这不会改变 finally 的行为。

标签: php error-handling try-catch


【解决方案1】:

简答

无论trycatch 块内部发生什么,Finally 块都保证在允许程序崩溃之前运行。

这里有一些解释:https://www.php.net/manual/en/language.exceptions.php 虽然解释不是特别详细。

更多细节

我想到的一个例子是,如果您正在处理输入/输出流或类似的东西,在使用后必须关闭以避免内存泄漏。使用您的示例:

try {
  memoryUser.startReading(someFileOrSomething);
}
catch (CustomException $customException) {
  // handle custom error
}
catch (Exception $exception) {
  // handle the error
  invisibleBug.whoops(); // i.e. something goes wrong in this block
}

memoryUser.Close(); // because something went wrong in the catch block,
                    // this never runs, which, in this case, causes a memory leak

在这种情况下,将memoryUser.Close(); 包装在finally 块中将确保该行将在程序的其余部分爆炸之前运行,即使在其他灾难性故障中也能防止内存泄漏。

TL;DR

所以很多时候,人们将 finally 块放在那里以确保一条重要的行运行,即使他们忽略了 catch 块中的某些内容。这是我一直看到它使用的方式。

希望这会有所帮助:)

【讨论】:

  • 只是为了确保我理解您所传达的内容,我没有看到的情况是在 catch 语句中发生错误时;在这种情况下,尽管出现了新的、未捕获的错误,finally 语句仍然可以运行?这意味着,您实际上应该使用 finally 语句,因为您不能总是预测 catch 语句中的错误?
  • 虽然语法看起来是Java,但这是一个很好的例子和解释。
  • Precisely :) 当你可能不需要 finally 块时,另一个可能的例外可能是如果 catch 非常简单(可能是 System.out.println("uh oh"); 但我通常更喜欢安全抱歉:) @亚当谢谢你和好眼光。我对 Java 比较熟悉,但认为这个概念是一样的。
  • @Jake - 有时你也不要写 catch 块。喜欢try { ... } finally {... }。然后异常将向上传播(在其他可以处理它的方法中捕获),但finally 块无论如何都会运行以清理需要清理的任何内容。
  • @Jake - 在其他时候,您没有完全处理异常。就像,你在你的catch 中做了一点(也许记录它或向异常对象添加一些细节),然后重新抛出异常,以便更高级别可以捕获它并正确处理它。 finally 再次清理。
【解决方案2】:

finally {} 块的特别之处在于它会始终try {} 块的末尾运行。

  • 如果try {}块中的代码成功完成,它将运行。

  • 如果try {} 块中的代码抛出被catch {} 捕获的异常,它将运行。 (finally {}catch {} 之后运行。)

  • 如果try {} 块中的代码抛出一个未被任何catch {} 块处理的异常,或者根本没有任何异常,它将运行。 (finally {} 块在异常传播到调用者之前运行。)

  • 如果try {}块中的代码抛出异常,并且catch {}中的代码抛出另一个异常(或再次抛出相同的异常),它将运行。 p>

  • 如果try {} 块或catch {} 块中的代码使用return,它甚至会运行。 (就像未捕获的异常一样,finally {} 在函数实际返回之前运行。)finally {} 块甚至可以使用return 本身,它的返回值将覆盖另一个块试图返回的值!

(有一种极端情况,finally {} 块不会运行,那就是整个进程都被破坏了,例如被杀死,或者调用 exit()die()。)

【讨论】:

  • 为了比较和对比问题中的两个 sn-ps,可能值得一提的是,在这些情况下,try/catch/finally 之后的常规代码将运行。 (前两个?我不确定。)
  • @ilkkachu 是的,只有前两个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 2013-09-20
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
相关资源
最近更新 更多