如何处理 Java 中的多个已检查异常?

How do I handle multiple checked exceptions in Java?

我写了这个方法,我想处理UnexpectedFormatExceptions:更具体地说,一个MissingFieldException、一个EmptyFieldException、一个UnknownCardTypeException、一个UnknownSpellCardException .

问题是我没有完全理解异常处理的思路。现在,我用构造函数等制作了 class UnexpectedFormatExceptions(如前所述)和 subclasses。我是否应该只添加一个 try 块来获取整个代码并为每个异常添加 catch 块?正确的做法是什么?

public ArrayList<Card> loadCardsFromFile(String path) throws IOException, FileNotFoundException, UnexpectedFormatException {
    String currentLine = "";
    FileReader fileReader = new FileReader(path);
    @SuppressWarnings("resource")
    BufferedReader br = new BufferedReader(fileReader);
    String[] currentsplit;
    ArrayList<Card> temp = new ArrayList<Card>();
    while ((currentLine = br.readLine()) != null) {
        currentsplit = currentLine.split(",");
        if (currentsplit[0].equals("Monster")) {
            MonsterCard x = new MonsterCard(currentsplit[1], currentsplit[2], Integer.parseInt(currentsplit[5]),Integer.parseInt(currentsplit[3]), Integer.parseInt(currentsplit[4]));
            temp.add(x);
        } 
        else {
            if (currentsplit[1].equals("Card Destruction")) {
                CardDestruction x = new CardDestruction(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
            if (currentsplit[1].equals("Change Of Heart")) {
                ChangeOfHeart x = new ChangeOfHeart(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
            if (currentsplit[1].equals("Dark Hole")) {
                DarkHole x = new DarkHole(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
            if (currentsplit[1].equals("Graceful Dice")) {
                GracefulDice x = new GracefulDice(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
            if (currentsplit[1].equals("Harpie's Feather Duster")) {
                HarpieFeatherDuster x = new HarpieFeatherDuster(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
            if (currentsplit[1].equals("Heavy Storm")) {
                HeavyStorm x = new HeavyStorm(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
            if (currentsplit[1].equals("Mage Power")) {
                MagePower x = new MagePower(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
            if (currentsplit[1].equals("Monster Reborn")) {
                MonsterReborn x = new MonsterReborn(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
            if (currentsplit[1].equals("Pot of Greed")) {
                PotOfGreed x = new PotOfGreed(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
            if (currentsplit[1].equals("Raigeki")) {
                Raigeki x = new Raigeki(currentsplit[1], currentsplit[2]);
                temp.add(x);
            }
        }   
    }
    return temp;
}

"But I don't fully understand the idea of handling exceptions."

Exception就是无法按照正常的程序流程进行。

因此,如果无法遵循正常流程,使用异常处理可以让您对 "not normal" 流程采取行动。

FileNotFoundException 是一种简单的尝试说明:

所以

try {
    ...statements to open a file and read its contents...
} catch (FileNotFoundException fnfe) {
    // maybe print out an error message to the user
    // or set a flag
    // etc
}

如果您不希望某个方法处理异常,则可以将异常处理委托给 'outer' 方法或调用者,方法是在代码中使用 'throw the Exception',但是在某个地方你需要做 try/catch 来处理它,就像我上面展示的那样。

But I don't fully understand the idea of handling exceptions.

打个比方:

正常代码流:

一列火车 运行 在轨道上。

异常流程:

火车脱轨(脱轨)

异常处理:

让火车回到正轨。


Should I just add a try block to take the whole code and catch blocks for each exception? or what should I do?

只捕获最后一个语句块的适当异常。尽量保持 try-catch 块尽可能小,并且只用适当的 try-catch 块围绕必要的代码块。

您也可以选择使用这个新语法 (Java 7):

try {
    // statements
} catch (MissingFieldException|EmptyFieldException|UnknownCardTypeException|UnknownSpellCardException ex) {
    logger.log(ex);
    throw ex;
}

异常是一个相当棘手的话题,至少在 IMO 看来,它很难掌握。经常会有关于抛出什么异常、在哪里处理它们或是否抛出它们(等等)的分歧。如果你想掌握它们,你可能需要大量阅读,尤其是用糟糕的异常方法来烧毁自己。有时我会相当通用,将很多设计决策留给您。但是,我针对您的代码提出了一些意见和建议。

Should I just add a try block to take the whole code and catch blocks for each exception?

No. No, no, no, NO!当您试图找出您的代码的哪一部分实际上抛出了 Exception 时,这可能会让您的生活变得艰难。但不仅如此。在 Google / 此处搜索 "try catch everything" 或类似内容以查看其他参数 - 我的回答已经足够长了。

就我个人而言,我会将您的方法分为三个:我有一个从文件读取并将内容放入 ArrayList<String> 的方法,然后我将传递 ArrayList<String>对于这种方法,我会尝试为 ArrayList 中的每个 String 创建一个 Card*。将它们分开也会使您的方法更容易进行(单元)测试。这是结构

public ArrayList<String> loadRowsFromFile(String path) throws IOException, FileNotFoundException {
    // whatever
}

// up to you if you want this to throw UnexpectedFormatException
public ArrayList<Card> loadCardsFromFile(ArrayList<String> cardsList) throws UnexpectedFormatException {
    // whatever
}

public Card buildCardFromString(String card) throws MissingFieldException, EmptyFieldException, UnknownCardTypeException, UnknownSpellCardException {
    // whatever
}

我认为如果您考虑一下您的方法契约会有所帮助:我的方法需要什么作为输入以及我的方法基于该输入产生什么?它应该与 any 输入一起使用吗?它是否应该只处理一些输入并抛出异常并让调用代码处理它们?如果 cardcardsListnull(或空),您可能想要抛出一个 IllegalArgumentException 或提供一些默认行为,具体取决于您的需要 - 您需要考虑它们.从 null / 空 String 中生成 Card 有意义吗?从 null / 空 cardsList 中得到 ArrayList<Card> 有意义吗?如果答案是 "No",一定要抛出(相关的)异常。不要为错误的输入发明解决方法。它会让你的代码成为一场噩梦。

这样分析最容易的是loadRowsFromFile。这是一种预期从文件中生成行列表的方法。但是如果 path 是无效的,那么继续下去就没有意义了,因为它不能履行它的合同:从无效的文件/路径中产生什么 ArrayList<Card> 是最明智的?一般来说,大概none。因此,抛出相关异常是有意义的。调用它的代码需要处理这个异常,或者,如果它不是预期的,或者如果处理这个异常没有多大意义,它应该将它抛到调用堆栈的更深处。

有特定的异常(如 MissingFieldExceptionEmptyFieldException 等)可能会清理您的代码并帮助调试和异常解决,但同样,这实际上取决于您想要在哪里或如何处理它们。例如,一层可能需要特定的异常,然后它将它们重新抛出到更高的地方,那里有一个 catch 用于更一般的异常。

*您可能真的想查看 factory method pattern.