2016-06-07 80 views
20

当在构造函数中打开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必须在构造函数中的第一条语句,这是不允许的。有没有什么好的方法来实现这一目标?

+2

我希望调用者提供输入流给'public B(InputStream in)'并关闭它。没有理由让派生类比基类更少用途。 – EJP

+0

功能更多,但使用起来也更麻烦。我可以支持这两种,但不具有'B(文件文件)'构造函数不是一个选项。 – Raniz

+2

在我看来,你的问题来自消耗A的构造函数内的流。如果不是这种情况,您只需将该流存储在一个实例变量中并设置“AutoClosable”。 –

回答

25

考虑使用静态工厂方法,而不是直接使用构造函数。使至少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; 
} 
+0

是啊,这似乎是要走的路 – Raniz

2

另一种方式去:

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); 
     } 
    } 
} 

我在这里张贴这是一个可能的答案,但是我在这里consdering:

  1. 可以更新的代码
  2. 你正在移动的构造函数的代码到init方法,由于受保护的空参数构造函数,只有子类必须正确处理对init的调用。有些人可能会认为设计不太好。我的观点是尽快对子类进行子类化,只有当你使用它时,你必须更多地了解它。
+0

正如你所说,它需要访问* A *的源代码,并且如果* A *中有最终变量需要从内容中初始化流。 – Raniz

+2

你应该使'init'' final',否则一个子类可以覆盖它并破坏'A'的构造函数。我认为这被称为构造泄漏或类似的东西。 – Oebele

+0

好点我加了它。 – Walfrat

-1

很遗憾,我手边没有编译器来测试,但是你可以不这样做,如下所示。

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)) 
    } 
} 
+3

不幸的是,在'file2stream'结束之前'try'块的结束,在文件被传递到'super'之前关闭文件。 –

+0

我可能会错过这个问题,但我认为这是重点。我解释了这样一个问题,即试图保护的唯一东西就是构建InputStream,如果不是这种情况怎么理解呢? – lijat

+1

我想,你不明白汉克德的评论。问题是,在试用资源中,打开的资源(流)在块的结尾处关闭。'return'语句并不妨碍这一点(或者对'try'没有任何意义)。所以当'file2stream'返回资源时,它已经被**关闭了。还要注意* try-with-resources *(这是为了关闭资源完成的)和* try-catch *之间的区别,这是为了捕获异常而完成的,而不是这里讨论的那个。 – RealSkeptic