首页 > 解决方案 > 当您尝试捕获块时,是否正在检查文件对象是否存在简化和不良样式?

问题描述

在尝试捕获之前检查文件对象是否存在是否过于多余并且被认为是不好的风格。因为如果文件对象不存在,无论如何都会调用 FileNotFoundException?

    if (!in.exists()) {
      System.err.println("Missing important input files!");
      System.exit(1);
    }

    try {
        int [] numbers = new int[100];

        Scanner input = new Scanner(in);
        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = input.nextInt();
        }
        input.close();

        Arrays.sort(numbers);

        PrintWriter output = new PrintWriter("output.txt");
        for (int i = 0; i < numbers.length; i++) {
            output.println(numbers[i]);
        }
        output.close();
    } catch (FileNotFoundException ex) {
        System.err.println("FileNotFoundException");
    }

标签: javaexceptionio

解决方案


是的,exists测试是多余的。隐式存在测试发生在Scanner. (实际上,它发生在打开文件的系统调用中。)

并且很难(而且方向错误)避免抓住IOException那个new Scanner(File)声明。那将是(IMO)非常糟糕的风格。

还有一点是在调用exists和打开文件之间存在“竞争条件”。可以想象,JVM 之外的其他东西可以在测试和打开尝试之间的短时间内创建或删除或重命名文件。这种东西过去曾在特权提升攻击中被利用。

这些可以“视为已读”。

因此,IMO,这里唯一真正的争议点是依赖例外来检查文件是否存在(在这种情况下)是否在风格上是错误的。


有些人会这样争论:

  1. 异常不应该用于流量控制;(参见https://wiki.c2.com/?DontUseExceptionsForFlowControl)。

  2. 测试丢失的文件是流控制。

  3. 因此,您不应为此使用 try / catch。

与此相反的论点是“不应将异常用于流量控制”应该真正说“不应将异常用于正常的流量控制”,并且处理边缘情况(例如丢失文件)不是正常的流量控制.

我们可以通过查看反对使用异常进行流控制的论点来打破这一点。主要有:

  • 可读性——try / catch代码比简单的测试更难阅读。我认为这不适用于这种情况。在这种情况下,无论如何您都必须处理异常。添加的exists测试只是添加代码,因此要阅读的代码更多,可读性更低。

  • 效率- 在 Java 中创建、抛出和捕获异常比简单的if测试更昂贵。有两个反驳:

    • 单个测试的效率很可能无关紧要。在这种情况下,可能节省的微秒是完全无关的。

    • 在这种情况下,我们还必须考虑exists在非异常情况下发生的冗余测试的成本。那是一个系统调用。通过避免异常处理,它可能比潜在的节省成本更高。如果我们假设输入文件通常存在,那么我们通常会付出性能损失。(算一算 ....)

  • “我不喜欢例外” 1 - 嗯,是的,但这不是一个有效的文体论点,所以我们不能用文体术语来解决它。

最后一个反驳论点是,如果 Java 设计者不打算在缺少所需文件的情况下使用异常,那么他们就不会声明 API 来引发异常。他们当然不会决定检查异常。


1 - 或者<insert_name_of_some_expert>认为他们不好。


推荐阅读