Java:异常和“可能尚未初始化”

时间:2012-03-23 05:30:54

标签: java

我是Java的新手。我正在编写一个程序来读取文件,计算其SHA1校验和,并将结果写入另一个文件。在任何错误上,我调用一个函数err_exit(),它向stderr输出一条消息,并通过调用具有指定退出状态的System.exit()来终止执行。这大约是我的main()函数的样子:

public static void main(String[] args) {
    String in_fname = "C:/tmp/test.txt"; // not reading args yet
    String out_fname = "C:/tmp/test.sign";
    byte[] file_data;
    String hexdigest;

    try {
        file_data = readFileAsByteArray(in_fname);
    }
    catch (java.io.IOException ex) {
        file_data = new byte[] {0};  // note this line well, please
        err_exit(2, "error opening input file '" + in_fname + "'");
    }

    try {
        hexdigest = hexdigestSha1(file_data);
    }
    catch (NoSuchAlgorithmException ex) {
        hexdigest = "";  // note this line well, please
        err_exit(3, "could not compute SHA1 message digest!");
    }

    try {
        writeFileFromString(out_fname, hexdigest);
    }
    catch (java.io.IOException ex) {
        err_exit(2, "error writing output file '" + out_fname + "'");
    }

    System.exit(0); // success
}

我要求你注意两行。这两行都只是为了防止编译器抱怨变量可能没有被初始化而存在。

就编译器而言,catch块可能会继续。实际上err_exit()将永远不会返回,因此无法传递无效值。

所以,我的问题是:处理这类事情的常用Java习语是什么? try / catch块的行有点难看;你会建议我让各种函数调用err_exit()而不是像这样明确的代码吗?我认为我更喜欢显式检查,而main()函数是进行检查的正确位置,但我对反馈感兴趣。

如果我要使用try / catch块,这是否可以使编译器警告静音?

如果我在Python中这样做,我可能只是没有捕获异常,并让程序停止堆栈跟踪。错误的堆栈跟踪不会让这个程序的用户感到震惊,因为该用户就是我。在我看来,如果我将main()函数声明为throws Exception,那么我就无法捕获异常,它会表现得像Python一样。这是一个可怕的想法,会让正确思考的Java人回避我吗?

P.S。如果你有一本喜欢的书/网页/我应该阅读的任何Java习语,请提及它。

编辑:我为带有下划线的变量名称道歉。我已经在我的真实节目中重命名了那些,但是我将把它们留在这里。这实际上是因为我花了很多时间用Python和C编程;我要么使用Python“PEP 8”风格或通用C风格,请选择。

4 个答案:

答案 0 :(得分:2)

您似乎拥有强大的C背景。我假设编译器抱怨变量,如file_data。只需在try-catch块上方添加 file_data = null

以上几点:

  1. 我认为将所有语句组合在一个块中是安全的。抛出异常时,程序将立即跳转到正确的异常块。它看起来也不那么难看了。
  2. 通常在catch-block中不会调用另一个方法,因为任务应该(通常并且如果可能的话)是简短的。处理错误,继续或退出(可能重新抛出异常)。
  3. System.exit()是邪恶的。如果您希望系统退出(即不可恢复的错误条件),则抛出一个包装的RuntimeException。 System.exit()可能导致非干净存在。而是使用抛出新的RuntimeException(e);
  4. 最后,如果我可能直截了当,Java约定是将方法/变量名称写为errExit,而不是err_exit。

答案 1 :(得分:2)

编译器理解throw永远不会返回,它不理解err_exit()不会返回。如果您使用忽略的异常重写,那么您的代码可能更清晰,编译器更快乐。 您还可以考虑使用Java命名约定。

public static void main(String[] args) {
  String inFname = "C:/tmp/test.txt"; // not reading args yet
  String outFname = "C:/tmp/test.sign";
  try {
    processFile(inFname, outFname);
  } catch (Exception e) {
    e.printStackTrace();
    throw e; // rethrow and let main() die
  }
}        

public static void processFile(String inFname, String outFname) 
    throws IOException, NoSuchAlgorithmException {
  Byte[] fileData = readFileAsByteArray(inFname);
  String hexDigest = hexdigestSha1(fileData);
  writeFileFromString(outFname, hexDigest);
}

在调用例程中,您可以捕获错误。如果你真的需要区分IOException可能发生的不同位置,那么你可以捕获你的例程并抛出描述性错误。

对代码的最小修复只是将变量初始化为设置它们的try catch块之外的null。然后编译器会很高兴。

答案 2 :(得分:2)

就个人而言,我喜欢“抛出空”;在调用一个根本无法返回的方法之后。

答案 3 :(得分:0)

如果我肯定我会在访问失败后立即退出,并且没有尝试代理对readFileAsByteArray等调用的结果,我可能会在以下位置分配空值申报网站。像这样......

byte[] file_data = new byte[] {0};

...代码的其余部分如下,没有catch块中的“伪造”分配。