简体   繁体   English

流关闭模式的变种在Java中

[英]Variants of stream closing pattern in Java

I often see the following pattern both in Java documentation and in other people's code when dealing with streams: 在处理流时,我经常在Java文档和其他人的代码中看到以下模式:

FileInputStream fis = null;
try {
  fis = new FileInputStream("some.file");
  // do something useful with fis
} finally {
  if (fis != null) {
    fis.close();
  }
}

However I personally prefer a different pattern: 但我个人更喜欢不同的模式:

FileInputStream fis = new FileInputStream("some.file");
try {
  // do something useful with fis
} finally {
  fis.close();
}

I like the brevity of the latter and I think it's correct. 我喜欢后者的简洁,我认为这是正确的。 But am I right about correctness? 但我对正确性是对的吗? Is there an objective reason to prefer one over another? 是否客观上有理由偏爱另一个?

Update 更新

Even if I write the examples pretty much how I would write such code in real life my pattern is still more concise. 即使我写的例子几乎是我在现实生活中编写这样的代码,我的模式仍然更简洁。 Compare the documentation approach: 比较文档方法:

public Object processFile(String fn) throws MyException {
  FileInputStream fis = null;
  try {
    fis = new FileInputStream(fn);
    return new Object(); // somehow derived from fis
  } catch (FileNotFoundException e) {
    throw new MySubExceptionForNotFound(e);
  } catch (IOException e) {
    throw new MySubExceptionForIoError(e);
  } finally {
    if (fis != null) {
      IOUtils.closeQuietly(fis);
    }
  }
}

with my approach: 用我的方法:

public Object processFile(String fn) throws MyException {
  try {
    FileInputStream fis = new FileInputStream(fn);
    try {
      return new Object(); // somehow derived from fis
    } finally {
      IOUtils.closeQuietly(fis);
    }
  } catch (FileNotFoundException e) {
    throw new MySubExceptionForNotFound(e);
  } catch (IOException e) {
    throw new MySubExceptionForIoError(e);
  }
}

Mine is one line shorter! 我的一行更短! :D :d

Interestingly my code does not change if you decide to use fis.close() instead of IOUtils.closeQuietly() while the "official" code will grow another 4 lines. 有趣的是,如果你决定使用fis.close()而不是IOUtils.closeQuietly() ,我的代码不会改变,而“官方”代码将增长另外4行。

The second example that you have posted would not try/catch the possible errors that ... = new FileInputStream("..."); 您发布的第二个示例不会尝试/捕获可能的错误... = new FileInputStream("..."); will return if it fails loading the file. 如果加载文件失败将返回。 In the first example though you automatically also catch the errors that the FileInputStream gives. 在第一个示例中,您可以自动捕获FileInputStream提供的错误。

I would personally go with the first one to have better error handling. 我个人会选择第一个更好的错误处理。

The second example does not compile unless you throw the exception from the method, because FileNotFoundException is a checked exception. 除非从方法中抛出异常,否则第二个示例不会编译,因为FileNotFoundException是一个已检查的异常。

Compile.java:5: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
        FileInputStream fis = new FileInputStream("some.file");

The first example also does not compile, because you are missing the appropriate catch block. 第一个示例也不编译,因为您缺少相应的catch块。 Here is a compiling example. 这是一个编译示例。

import java.io.*;
public class Compile {

    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("some.file");
            // do something useful with fis

            if (fis != null) {
                fis.close();
            }
        }
        catch (FileNotFoundException fnf) {
        }
        catch (IOException ioe) {
        }
        finally {
        }
    }
}

Use try-with-resources : 使用try-with-resources

try (FileInputStream fis = new FileInputStream("some.file")) {
    // some code here
}

To answer the question of why the recommended pattern is the way it is, consider the fact that new FileInputStream(String) throws a checked exception that you should probably catch; 要回答推荐模式为何如此的问题,请考虑new FileInputStream(String)抛出一个您应该捕获的已检查异常的事实; The

FileInputStream fis = null;
try {
    fis = new FileInputStream("somefile.txt");
} catch (FileNotFoundException e) {
    return false;
} finally {
    if (fis != null) {
        fis.close();
    }
}

allows you to handle it in the same try/catch block as your other file-related exceptions. 允许您在与其他文件相关的异常相同的try / catch块中处理它。 This has brevity and reduced nesting advantages over the following: 与以下相比,它具有简洁和减少嵌套优势:

try {
    FileInputStream fis = new FileInputStream("some.file");
    try {
        // do something useful with fis
    } finally {
        fis.close();
    }
} catch (FileNotFoundException e) {
    return false;
}

And if you're not catching the exception and just letting it propagate, then your suggestion is cleaner - however given the heavy use of checked exceptions in the IO libraries (including from class constructors), catching and handling an exception is common enough, and I think it makes sense to have just one pattern for tutorial purposes instead of showing someone a slightly different pattern each time. 如果你没有捕获异常而只是让它传播,那么你的建议就更清晰 - 但是由于在IO库中大量使用了检查异常(包括来自类构造函数),捕获和处理异常是很常见的,并且我认为只有一个模式用于教学目的而不是每次都向某人显示略有不同的模式是有意义的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM