我知道涉及在try / catch / finally块中返回的令人头疼的问题 - finally中的返回始终是方法的返回,即使try或catch块中的返回应该是执行的返回
但是,同样适用于System.exit()?例如,如果我有一个try块:
try {
//Code
System.exit(0)
}
catch (Exception ex) {
//Log the exception
}
finally {
System.exit(1)
}
如果没有异常,将调用哪个System.exit()?如果exit是return语句,则System.exit(1)行将始终(?)被调用。但是,我不确定退出的行为是否与返回不同。
代码处于极端情况下,即使不是不可能,也很难再现,因此我无法编写单元测试。我今天晚些时候会尝试进行一项实验,如果我得到一些免费的分钟,但我很好奇,也许有人知道答案,可以提供它,或者我无法运行实验
答案 0 :(得分:74)
没有。 System.exit(0)
不会返回,并且不会执行finally块。
System.exit(int)
可以抛出SecurityException
。如果发生这种情况,将执行finally块 。并且由于相同的主体在同一代码库中调用相同的方法,因此第二次调用可能会抛出另一个SecurityException
。
以下是第二种情况的示例:
import java.security.Permission;
public class Main
{
public static void main(String... argv)
throws Exception
{
System.setSecurityManager(new SecurityManager() {
@Override
public void checkPermission(Permission perm)
{
/* Allow everything else. */
}
@Override
public void checkExit(int status)
{
/* Don't allow exit with any status code. */
throw new SecurityException();
}
});
System.err.println("I'm dying!");
try {
System.exit(0);
} finally {
System.err.println("I'm not dead yet!");
System.exit(1);
}
}
}
答案 1 :(得分:8)
包括catch
在内的简单测试也表明,如果system.exit(0)
没有抛出安全异常,它将是最后执行的语句(catch
和finally
未执行全部)。
如果system.exit(0)
确实抛出安全异常,则执行catch
和finally
语句。如果catch
和finally
都包含system.exit()
语句,则只会执行这些system.exit()
语句之前的语句。
在上述两种情况下,如果try
代码属于另一种方法调用的方法,则被调用的方法不会返回。
更多详情here(个人博客)。
答案 2 :(得分:4)
其他答案涵盖catch
和finally
阻止如果System.exit
退出JVM而不抛出SecurityException
而无法运行的方式,但他们不会#39} ; t显示"尝试使用资源"阻止资源:他们关闭了吗?
翻译的效果是将资源规范放在内部" try语句。这允许扩展的try-with-resources语句的catch子句捕获由于自动初始化或关闭任何资源而导致的异常。
此外,所有资源都将在执行finally块时关闭(或尝试关闭),与finally关键字的意图保持一致。
也就是说,在close
或catch
块运行之前,资源将为finally
d。即使close
和catch
不运行,如果他们finally
某种情况怎么办?
这里提供了一些代码来证明资源中的资源"尝试使用资源"声明也没有结束。
我使用一个简单的BufferedReader
子类,在调用super.close
之前打印一个语句。
class TestBufferedReader extends BufferedReader {
public TestBufferedReader(Reader r) {
super(r);
}
@Override
public void close() throws IOException {
System.out.println("close!");
super.close();
}
}
然后我在try-with-resources语句中设置了调用System.exit
的测试用例。
public static void main(String[] args)
{
try (BufferedReader reader = new TestBufferedReader(new InputStreamReader(System.in)))
{
System.out.println("In try");
System.exit(0);
}
catch (Exception e)
{
System.out.println("Exception of type " + e.getClass().getName() + " caught: " + e.getMessage());
}
finally
{
System.out.println("finally!");
}
}
输出:
尝试
因此,catch
和finally
块不仅不会运行,而且#34;尝试使用资源"如果close
成功,则声明无法获得System.exit
资源。
答案 3 :(得分:3)
最终块将被执行无论什么....即使try块抛出任何throwable(异常或错误).....
只有case finally块不执行...是我们调用System.exit()方法..
try{
System.out.println("I am in try block");
System.exit(1);
} catch(Exception ex){
ex.printStackTrace();
} finally {
System.out.println("I am in finally block!!!");
}
它不会执行finally块。该计划将被终止 在System.exit()语句之后。
答案 4 :(得分:2)
如果您认为这种行为有问题,并且您需要对System.exit
调用进行精细控制,那么您唯一能做的就是将System.exit功能包装在您自己的逻辑中。如果我们这样做,我们可以最终执行块执行并在退出流程中关闭资源。
我正在考虑做的是包裹System.exit
电话&我自己的静态方法中的功能。在exit
的实现中,我将抛出Throwable
或Error
的自定义子类,并使用Thread.setDefaultUncaughtExceptionHandler
实现自定义Uncaught异常处理程序来处理该异常。因此,我的代码变为:
//in initialization logic:
Thread.setDefaultUncaughtExceptionHandler((thread, exception) -> {
if(exception instanceof SystemExitEvent){
System.exit(((SystemExitEvent)exception).exitCode);
}
})
// in "main flow" or "close button" or whatever
public void mainFlow(){
try {
businessLogic();
Utilities.exit(0);
}
finally {
cleanUpFileSystemOrDatabaseConnectionOrWhatever();
}
}
//...
class Utilities {
// I'm not a fan of documentaiton,
// but this method could use it.
public void exit(int exitCode){
throw new SystemExitEvent(exitCode);
}
}
class SystemExitEvent extends Throwable {
private final int exitCode;
public SystemExitEvent(int exitCode){
super("system is shutting down")
this.exitCode = exitCode;
}
}
这个策略增加了使这个逻辑可测试的“好处”:测试包含我们的“主流”的方法实际上是要求系统退出,我们所要做的就是捕获一个throwable并断言这是写类型。例如,我们的业务逻辑包装器的测试可能如下所示:
//kotlin, a really nice language particularly for testing on the JVM!
@Test fun `when calling business logic should business the business`(){
//setup
val underTest = makeComponentUnderTest(configureToReturnExitCode = 42);
//act
val thrown: SystemExitEvent = try {
underTest.mainFlow();
fail("System Exit event not thrown!")
}
catch(event: SystemExitEvent){
event;
}
//assert
assertThat(thrown.exitCode).isEqualTo(42)
这种策略的主要缺点是它是一种从异常流中获取功能的方法,这通常会产生意想不到的后果。在这种情况下,最明显的一点是,您编写try { ... } catch(Throwable ex){ /*doesnt rethrow*/ }
的任何地方都必须进行更新。对于具有自定义执行上下文的库,需要对其进行改进以了解此异常。
总的来说,这对我来说似乎是一个好策略。这里有其他人这么认为吗?
答案 5 :(得分:0)
在下面的示例中,如果System.exit(0)
在异常行之前,则程序将正常终止,因此FINALLY将不会执行。
如果System.exix(0)
是try块的最后一行,这里有2个场景
package com.exception;
public class UserDefind extends Exception {
private static int accno[] = {1001,1002,1003,1004,1005};
private static String name[] = {"raju","ramu","gopi","baby","bunny"};
private static double bal[] = {9000.00,5675.27,3000.00,1999.00,1600.00};
UserDefind(){}
UserDefind(String str){
super(str);
}
public static void main(String[] args) {
try {
//System.exit(0); -------------LINE 1---------------------------------
System.out.println("accno"+"\t"+"name"+"\t"+"balance");
for (int i = 0; i < 5; i++) {
System.out.println(accno[i]+"\t"+name[i]+"\t"+bal[i]);
//rise exception if balance < 2000
if (bal[i] < 200) {
UserDefind ue = new UserDefind("Balance amount Less");
throw ue;
}//end if
}//end for
//System.exit(0);-------------LINE 2---------------------------------
}//end try
catch (UserDefind ue)
{
System.out.println(ue);
}
finally{
System.out.println("Finnaly");
System.out.println("Finnaly");
System.out.println("Finnaly");
}
}//end of main
}//end of class