【问题标题】:How to handle exceptions when reading files with buffered reader?使用缓冲阅读器读取文件时如何处理异常?
【发布时间】:2018-05-18 17:17:07
【问题描述】:

我编写了从文本文件中读取文本(json、xml 等)的代码,并将其转换为字符串,然后其他代码可以使用该字符串将其转换为由 jackson 注释的普通旧 java 对象或 POJOS .

我不确定我的代码是否正确处理了异常。到目前为止,我已经使用了在我的代码之后提到的原则(请阅读 DOWN VOTERS !!!)来开发代码。请注意,我不能对资源使用 try,因为我坚持使用 Java 6(即使我的项目 JRE 是 1.8)。

package com.testing;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class JunkEx {

    public static void main(String[] args) {
        String filePath = ".\\src\\test\\resources\\text-files\\orders\\orders-2017.txt";
        String contents = fileToString(filePath);
        System.out.println(contents);
    }

    private static String fileToString(String filePath) {
        StringBuilder stringBuilder = null;
        BufferedReader br = null;

        try {
        br = new BufferedReader(new FileReader(filePath));
        stringBuilder = new StringBuilder();
        String currentLine;
        while ((currentLine = br.readLine()) != null) {
            stringBuilder.append(currentLine);
            stringBuilder.append("\n");
        }

        }catch (FileNotFoundException ex1) {
            ex1.printStackTrace();
        }catch (IOException ex2) {
            ex2.printStackTrace();
        }finally {
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return stringBuilder.toString();
    }

}

原则

1) 首先捕获最具体的异常,然后是异常层次结构中高于它的异常。即第一次捕获 FileNotFoundException 和稍后捕获 IOException。 Refer point 5 here

2) 不要从 finally 块内部返回,因为只要 try 完全或突然“完成”,finally 总是会执行。 Refer this SO answer.

3) 清理 finally 块中的缓冲读取器等资源。 Refer point 1 here.

4) 不要让“危险”方法的调用者(即可能抛出异常),必须知道/抛出其中的每个异常。即危险方法不应该“抛出 FileNotFoundException、IOException...等”。 refer this link, specifically the last paragraph

代码中的缺陷: 如果前两个 catch 块中的任何一个被执行,那么很可能整个文件都没有被读取。但是,我的方法无论如何都会返回一个字符串。字符串可能为空或不完整。

问题 -

1) 我想在文本文件未成功转换为字符串时抛出异常,即执行三个 catch 块之一。我应该将异常包装在通用 Exception 对象内的每个 catch 块中并抛出它还是做其他事情?

2)如何改进/修复此代码的异常处理?

项目结构

【问题讨论】:

  • 请说明为什么我得到了反对票。我努力阅读并找出如何编写我的代码。我所要求的只是修复/改进它的提示或指示。我该如何改进这个问题?

标签: java exception


【解决方案1】:

简单的答案:根本不捕获异常。让来电者抓住他们。他是需要知道的人,并且知道如何处理他们。这个方法肯定不行。

4) 不要让“危险”方法的调用者(即可能抛出异常),必须知道/抛出其中的每个异常。即危险方法不应该“抛出 FileNotFoundException、IOException...等”。参考这个链接,特别是最后一段。

我不怎么重视这个“原则”,而且无论如何它实际上并不适用于此。抛出的唯一异常是IOExceptionFileNotFoundException,它们是从它派生的。如果他不想,呼叫者不必同时处理这两个问题。然而,他可能希望完全这样做,例如,如果丢失的文件构成部署错误。

【讨论】:

  • 我也想让这些错误信息变得友好。我将所有异常都包含在这样的 IOException 中 - throw new IOException("Erorr: What happens here : ", exception);现在调用者只需要捕获 IOException。这够好吗?
  • 没有。调用者最好完全处理异常。他是想读取文件的人,他知道此时应用程序的功能是什么,文件的实际用途是什么,并且对错误消息应该说什么有更好的了解。而且,他只需要抓住IOException,所以负担并不像你想象的那样。 Catch-log-throw 经常被认为是不好的做法。即使您向用户显示不同的消息,您至少应该记录原始异常。如果可能,最好显示异常自己的消息。
  • 我一读到你的原则 #4 就打算这么说。这是错误的。如果您不确切知道如何处理异常,只需将其传递给更高级别的层。如果您确实知道如何处理异常,则不需要“原则”来告诉您该怎么做。通常,最高层向用户显示错误对话框或记录错误并静默失败。但如果你不知道预期的结果,不要试图隐藏错误:通过抛出问题将问题发送到知道的层。
  • @EJP - 仅供参考,此页面中似乎存在错误。我对您的回答的赞成将您的分数提高到了两分。当我不小心点击了你的答案时,它使你的分数为零。我刷新了我的Firefox浏览器,问题仍然存在。
【解决方案2】:

你有两个选择:

  1. 不要捕获异常,让调用者处理它们
  2. 捕获异常并抛出您自己的自定义异常,例如FileToStringFailedException包装实际异常。包装部分非常重要,因此当调用链上的某个人执行 printStackTrace() 时,您会得到一个 Caused By 部分来解释真正的失败。

任何一个选项都有效,您选择哪一个取决于整体设计。对于一些简单的事情,我只是让异常向上渗透;如果我正在设计一个带有其他自定义包装异常的大型复杂库,我可能会选择选项 2。

如果没有更多关于您正在做什么以及这适合您的系统的上下文,就不可能说一个选项“更好”。

无论您做什么,绝不会干扰实际的异常。例外是针对程序员的,而不是针对用户的。如果您希望用户出现“友好”错误,请在向用户显示异常时执行此操作,但请确保为程序员记录原始异常。否则,当您的“友好”异常隐藏了解决问题所需的关键信息时,您会后悔不已。

【讨论】:

  • 我编写了从文本文件中读取文本(json、xml 等)的代码,并将其转换为字符串,然后其他代码可以使用该字符串转换为普通的旧 java 对象或 POJOS由杰克逊注释的。
  • 我也想让这些错误信息变得友好。我想知道将所有异常包装在 IOException 中是否是个好主意,就像这样 - throw new IOException("Erorr: What happens here", exception);现在调用者只需要捕获 IOException。这种包装可以/可取吗?
  • 我刚刚注意到,如果try中的第一行由于FileNotFound之类的异常甚至没有运行,那么stringBuilder将为null,调用代码将抛出一个空指针异常。该功能的用户永远不会知道真正导致问题的原因。 :(
  • 这强调了这个方法必须以某种方式抛出异常。
猜你喜欢
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-20
  • 2016-01-23
  • 2017-03-24
  • 2021-06-30
  • 2013-12-13
相关资源
最近更新 更多