调用超级构造函数时尝试使用资源

Try-with-resources when calling super constructor

在构造函数中打开 InputStream 然后将其传递给超级构造函数时,是否有使用 try-with-resources 的好方法?

基本上我想做的是:

public class A {
    public A(InputStream stream) {
        // Do something with the stream but don't close it since we didn't open it
    }
}

public class B {
    public B(File file) {
        // We open the stream so we need to ensure it's properly closed
        try (FileInputStream stream = new FileInputStream(file)) {
            super(new FileInputStream(file));
        }
    }
}

但是,当然,因为 super 必须是构造函数中的第一条语句,所以这是不允许的。有什么好的方法可以实现吗?

考虑使用静态工厂方法而不是直接使用构造函数。至少将 B 的构造函数设为私有,并创建一个方法,例如

private B(InputStream is) {
    super(is);
    // Whatever else is needed
}

public static B newInstance(File file) {
    B result;
    try (FileInputStream stream = new FileInputStream(file)) {
        result = new B(stream);
    }
    // Further processing
    return result;
}

另一种方法:

public class A {
    protected A(){
        // so he can't be called from the outside, subclass ensure that init is done properly.
    }

    public A(InputStream stream) {
        init(stream);
    }
    // not be able to call it from outside
    protected final init(InputStream is){
        //here goes the code
    }
}

public class B {
    public B(File file) {
        // We open the stream so we need to ensure it's properly closed
        try (FileInputStream stream = new FileInputStream(file)) {
            init(stream);
        }
    }
}

我在这里发布这个作为可能的答案,但是我在这里考虑:

  1. 你可以更新A的代码
  2. 您正在将构造函数的代码移动到 init 方法,这要归功于受保护的空 arg 构造函数,只有子类必须正确处理对 init 的调用。有些人可能会认为它的设计不太好。我的观点是,一旦你对某些东西进行子类化,你就必须在使用它的时候更多地了解它。

遗憾的是我手头没有编译器可以测试,但你能不能不这样做。

public class B {
    private static InputStream file2stream(File f){
        // We open the stream so we need to ensure it's properly closed
        try (FileInputStream stream = new FileInputStream(file)) {
            return stream;
        }catch(/*what you need to catch*/){
             //cleanup
             // possibly throw runtime exception
        }
    }
    public B(File file) {
        super(file2stream(file))
    }
}