【问题标题】:How do I refactor closing a stream in Java?如何在 Java 中重构关闭流?
【发布时间】:2011-04-28 22:34:30
【问题描述】:

由于我公司使用 Eclipse 和使用 Eclipse 的 code-autofix 的政策,以下代码模式在代码库中出现过多:

InputStream is = null;
try {
    is = url.openConnection().getInputStream();
    // .....
} catch (IOException e) {
    // handle error
} finally {
    if (is != null) {
        try {
            is.close();
        } catch (IOException e) {
            // handle error
       }
    }
}

IMO 它非常丑陋且难以阅读,尤其是 finally 块中的部分(真的需要捕获 2 个 IOException 实例吗?)。有没有办法精简代码,让它看起来更干净?

【问题讨论】:

  • 请注意,除非经过多个实体的测试和批准,否则我不能使用 Apache IOUtils 等外部库
  • 使用 Apache IOUtils 的全部意义在于它已经被无数其他人测试过了。话虽如此,我感受到了你的痛苦。让 IOUtils 在您的组织内测试和批准一次,这样您就可以在所有项目中使用它,难道不值得吗?
  • 如果生活就这么简单……我必须经历许多层级的管理和繁文缛节,才能让相关工作组看到它。由于多年前已经退役的软件存在“遗留”问题,我们仍然无法使用 JDK1.4.2
  • @Bill the Lizard:+1,打好仗。
  • @david:为你的老板打印一份副本并放入他们的收件箱:oracle.com/technetwork/java/eol-135779.html

标签: java refactoring error-handling stream


【解决方案1】:

查看此question,使用closeQuietly() 解决方案。

InputStream is = null;
try {
    is = url.openConnection().getInputStream();
    // .....
} catch (IOException e) {
    // handle error
} finally {
    IoUtils.closeQuietly(is);
}

// stolen from the cited question above
public class IoUtils {

  public static closeQuietly (Closeable closeable) {
    try {
      closeable.close();
    } catch (IOException logAndContinue) {
      ...
    }
  }
}

或者等待JDK7's ARM blocks。

【讨论】:

    【解决方案2】:

    首先,关于使用IOUtils - 可能值得一试,告诉你的主管他们可能使用的应用程序服务器/Java 运行时环境,使用IOUtils 和类似的库本身。所以本质上你并没有在你的架构中引入新的组件。

    第二,不,不是。除了编写自己的实用程序来模仿 IOUtils 的 closeQuietly 方法之外,实际上没有其他办法。

    【讨论】:

    • 嘿,如果 closeQuietly 是开源的,请将其复制到您的项目中。
    • ...可重用性和模块化的发明者安息在他的坟墓里......
    • close 静静地忽略异常。这从来都不是一个好习惯。此外,大卫想“处理错误”。
    【解决方案3】:
    public class Util {
        public static void closeStream(inputStream is) {
            if (is != null) {
                try {
                   is.close();
                } catch (IOException e) {
                   // log something
            }
        }
    }
    

    现在你的代码是

    InputStream is = null;
    try {
        is = url.openConnection().getInputStream();
        // .....
    } catch (IOException e) {
        // handle error
    } finally {
        Util.closeStream(is);
    }
    

    没有什么可做的,因为 catch 中的 IOException 可能有一些特定的处理。

    【讨论】:

    • 我喜欢这个,但我倾向于更进一步,并创建 Util.openStream(url) 以便调用者不会在 2 个不同的抽象级别上操作。
    【解决方案4】:

    为什么要做任何事情?这是工作代码。没错。

    别这样。

    【讨论】:

    • 对于反论点,klocwork.com/blog/2010/10/…
    • 他没有问“我该怎么做”,而是问“我该怎么做。”
    • 我在问为什么。为什么要对干扰工作代码进行预算?在那工作生成代码。我个人将生成的代码视为目标代码,我不会乱用它。
    【解决方案5】:

    你可以在某处定义这样的东西:

    private static interface InputStreamCallback {
    
        public void doIt(InputStream is) throws IOException;
    
    }
    
    private void with(InputStreamCallback cb) {
    
        InputStream is = null;
    
        // Creational code. Possibly adding an argument
    
        try {
            cb.doIt(is);
        } catch (IOException e) {
            // handle error or rethrow.
            // If rethrow add throws to method spec.
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    // handle error or rethrow.
                }
            }
        }
    }
    

    然后像这样调用你的代码:

    with(new InputStreamCallback() {
    
        @Override
        public void doIt(InputStream is) throws IOException {
            is = url.openConnection().getInputStream();
            // .....
        }
    
    });
    

    如果您在辅助类中使用方法static 声明,那么您甚至可以对其进行import static。

    有一个缺点。你需要声明url final。

    编辑:创建代码不是重点。您可以通过多种方式安排它。回调是重点。您可以在那里隔离您需要做的事情。

    【讨论】:

      猜你喜欢
      • 2010-10-05
      • 1970-01-01
      • 2016-01-23
      • 1970-01-01
      • 1970-01-01
      • 2012-07-01
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多