在 Java 中,如何强制异常“冒泡”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24194626/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 10:44:18  来源:igfitidea点击:

In Java, how to force an Exception to "bubble up"?

javaexception

提问by Alexander Mills

I have a method that throws an Exception, which calls a method which throws an Exception, etc etc. So several methods that "throw Exception" are daisy-chained. The first method that calls the submethod, puts that submethod in a try-catch block that catches any Exceptionthat gets thrown inside that call. IN THEORY. In practice, no Exception is being caught by that try-catch block. Is there a way to remedy that?

我有一个抛出异常的方法,它调用一个抛出异常的方法,等等。所以几个“抛出异常”的方法是菊花链的。调用子方法的第一个方法将该子方法放在一个 try-catch 块中,该块捕获Exception在该调用中抛出的任何内容。理论上。实际上,该 try-catch 块不会捕获任何异常。有没有办法补救?

Here is the code:

这是代码:

          try {
                CSVSingleton.tryToReadBothFiles(FILE1_PATH, FILE2_PATH);

                } catch (Exception e) { // THIS BLOCK NEVER GETS ENTERED BY THE PATH O EXECUTION
System.out.println("There was an exception reading from at least one of the files. Exiting.");
                    System.exit(0);
                }

here is the method from the CSVSingleton class:

这是来自 CSVSingleton 类的方法:

public static void tryToReadBothFiles(String filePath1, String filePath2) throws Exception {

        file1 = new CSVFileForDwellTime1(filePath1);
        file2 = new CSVFileForDwellTime2(filePath2);
    }

And here is code from the CSVFileForDwellTime1 class:

这是来自 CSVFileForDwellTime1 类的代码:

public CSVFileForDwellTime1(String filePath) throws Exception {
        super(filePath);
    }

and then here is the code that actually throws an original FileNotFoundException:

然后这里是实际抛出原始 FileNotFoundException 的代码:

public GenericCSVFile(String filePath) throws Exception{
        this.filePath = filePath;
        try {
            fileReader = new FileReader(filePath);
            csvReader = new CSVReader(
                    fileReader);
            header = getActualHeaderNames();
        } catch (FileNotFoundException e) {
            System.out.println("Could not read file with name: " + filePath);
            // e.printStackTrace();
        }
    }

My guess is that the FileNotFoundException in the last method is caught by the catch block and so doesn't "bubble up". But is there a way to force it to bubble up?

我的猜测是最后一个方法中的 FileNotFoundException 被 catch 块捕获,因此不会“冒泡”。但是有没有办法强迫它冒泡?

采纳答案by RossBille

Immediate answer:

立即答复:

Your thought is exactly right,

你的想法完全正确

    try {
        fileReader = new FileReader(filePath);
        csvReader = new CSVReader(
                fileReader);
        header = getActualHeaderNames();
    } catch (FileNotFoundException e) {
        System.out.println("Could not read file with name: " + filePath);
        // e.printStackTrace();
    }

This suppresses the exception Either remove the try-catchblock (desired unless you can actually do something with the exception)or re-throw it within the catchblock.

这会抑制异常要么删除try-catch块(除非您实际上可以对异常执行某些操作,否则需要)或在catch块中重新抛出它。

Explanation

解释

Generally with checkedexceptions like this you have 2 options

通常,checked除了像这样的例外,您有 2 个选择

  1. Catch the exception and do something to remedy the exception
  2. Throw the exception to the caller
  1. 捕获异常并做一些事情来补救异常
  2. 向调用者抛出异常

What you have done here falls into the 1st category except that you have not done anything useful in the catchblock (printing to console is rarely useful in this case because the exception message itself normally has enough information to see what has gone wrong)

你在这里所做的属于第一类,除了你没有在catch块中做任何有用的事情(在这种情况下打印到控制台很少有用,因为异常消息本身通常有足够的信息来查看出了什么问题)

The 2nd category is achieved either by not using a try-catchblock and thus adding throws FileNotFoundExceptionto the method signature. Alternatively explicitly throwthe exception that you caught using:

第二类是通过不使用try-catch块并因此添加throws FileNotFoundException到方法签名来实现的。或者throw,您使用以下方法明确捕获的异常:

catch(FileNotFoundException e)
{
    //do something
    throw e;
}

however in this case if do somethingisn't worthwhile you have unnecessarily caught something just to throw it on.

但是在这种情况下,如果do something不值得,你不必要地抓住了一些东西只是为了扔掉它。

You can think of it like this:

你可以这样想:

Alice throws a ball to Charlie
Bob intercepts the ball
Bob then looks at the ball and then throws it to Charlie

Bonus Points

奖励积分

When you know the exception that could occur make sure to actually catchor throwthat exception and not a parent of that exception. Take the following method signatures for example:

当您知道可能发生的异常时,请确保实际catchthrow该异常而不是该异常的父级。以下面的方法签名为例:

public String method1() throws Exception

public String method2() throws FileNotFoundException

Here method2clearly tells the caller what could happen and can help then figure out why the exception is being called (without having to read through the code or experience the error).

这里method2清楚地告诉调用者可能发生什么,然后可以帮助找出调用异常的原因(无需通读代码或遇到错误)。

Secondly other exceptions can occur and you are potentially catching the wrong exception, take the following example:

其次,可能会发生其他异常,您可能会捕获错误的异常,请看以下示例:

try{
    fileReader = new FileReader(filePath); //could potentially throw FileNotFoundException
    fileReader = null; //woops
    csvReader = new CSVReader(fileReader); //throws NullPointerException but the compiler will not know this 
    //....other stuff....//
}
catch(Exception e){
    // the compiler told me that a FileNotFoundException can occur so i assume that is the reason the catch has executed
    System.err.println("You have entered an invalid filename");
    //doing anything here that would fix a FileNotFoundException is pointless because that is not the exception that occured
}

回答by M Anouti

Technically you just need to add throw eright after System.out.println("Could not read file with name: " + filePath);and the exception will propagate up to the first method.

从技术上讲,你只需要添加throw e之后System.out.println("Could not read file with name: " + filePath);,异常将传播到第一个方法。

However, this would not be a clean way to handle the exception, because in this case all you'd be doing is printing an error message at the cost of changing the location of the original FileNotFoundException. Ideally, when you need to inspect an exception stacktrace, you expect a line of code throwing an exception to be the actualline that really caused the exception.

但是,这不是处理异常的干净方法,因为在这种情况下,您所做的只是以更改原始FileNotFoundException. 理想情况下,当您需要检查异常堆栈跟踪时,您希望抛出异常的代码行是真正导致异常的实际行。

The throws Exceptionin the method declaration should be considered part of the contract of the method, i.e. it describes a possible behavior of the method. You should always ask yourself: Does it make sense for a FileNotFoundExceptionto be specified as a possible exceptional behavior for the method/constructor I'm writing? In other words, do I want to make the caller of my method aware of this exception and leave it to the caller to deal with it? If the answer is yes (and in this case I would say it makes sense), then avoid wrapping the code in a try-catchblock. If no, then your catchblock should be responsible for dealing with the exception itself. In this specific example IMO there is not much you can do in the catchstatement, so just remove the try-catch.

throws Exception方法声明应被视为法的合同的一部分,也就是说,它描述了该方法的一个可能的行为。您应该始终问自己:将 aFileNotFoundException指定为我正在编写的方法/构造函数的可能异常行为是否有意义?换句话说,我是否想让我的方法的调用者知道这个异常并将它留给调用者来处理?如果答案是肯定的(在这种情况下我会说这是有道理的),那么避免将代码包装在一个try-catch块中。如果不是,那么您的catch块应该负责处理异常本身。在这个特定的例子中,IMO 在catch语句中没有什么可以做的,所以只需删除try-catch.

As mentioned by others, you should declare the most specificexception in the method signature (throws FileNotFoundExceptioninstead of throws Exception).

正如其他人所提到的,您应该在方法签名中声明最具体的异常(throws FileNotFoundException而不是throws Exception)。

回答by NESPowerGlove

You can rethrow the exception once you catch it, for callees further up the stack to handle. You can change what exception it is too if a new type of exception makes more sense at a higher level.

您可以在捕获异常后重新抛出异常,以便在堆栈上进一步处理的被调用者进行处理。如果新类型的异常在更高级别更有意义,您也可以更改它是什么异常。

catch (SomeSpecificException e)
{
    some code here
    throw new AMoreBroadException("I really need the callee to handle this too");
}

回答by user2864740

Use a throwin the catch clause.

throw在 catch 子句中使用 a 。

} catch (FileNotFoundException e) {
    System.out.println("Could not read file with name: " + filePath);
    // Continue up, Mr. Exception!
    throw e;
}

Alternatively, wrap the exception as appropriate (since an IOException is checked this handy here) - this is called a Chained Exception. Then, depending on what is thrown, the throws Exceptioncan be removed from the method signature.

或者,适当地包装异常(因为在这里检查 IOException 很方便) - 这称为Chained Exception。然后,根据抛出的内容,throws Exception可以从方法签名中删除 。

throw new RuntimeException("Could not read file: " + filePath, e);

回答by Zyl

If you don't want to catch it, then don't. Alternatively, you can just throw it again with a throw-statement. You can also throw a new Exception of any class you like. You should only catch an Exception at a level where you can react to it properly. As you found out, catching it at that low level is not helpful, so do not catch it there.

如果你不想抓住它,那就不要。或者,您可以使用 -throw语句再次抛出它。您还可以抛出您喜欢的任何类的新异常。您应该只在可以对其做出正确反应的级别上捕获异常。正如您所发现的,在那个低级别捕获它没有帮助,所以不要在那里捕获它。