关于java中关闭流疑问

下面这段代码的作用是压缩,会用到ZipOutputStream

    ZipOutputStream zipOutputStream = null;

try {

zipOutputStream = new ZipOutputStream(new FileOutputStream(zipPath));

} catch (FileNotFoundException e) {

throw new IllegalArgumentException("zipPath error " + "", e);

} finally {

if (null != zipOutputStream) {

try {

zipOutputStream.close();

} catch (IOException e) {

logger.error("", e);

}

}

}

错误放大版1:

    ZipOutputStream zipOutputStream = null;

try {

FileOutputStream fileOutputStream = new FileOutputStream(zipPath);

throw new RuntimeException();

zipOutputStream = new ZipOutputStream(fileOutputStream);

} catch (FileNotFoundException e) {

throw new IllegalArgumentException("zipPath error " + "", e);

} finally {

if (null != zipOutputStream) {

try {

zipOutputStream.close();

} catch (IOException e) {

logger.error("", e);

}

}

}

错误放大版2:

    ZipOutputStream zipOutputStream = null;

try {

zipOutputStream = new ZipOutputStream(new FileOutputStream(zipPath),null);

} catch (FileNotFoundException e) {

throw new IllegalArgumentException("zipPath error " + "", e);

} finally {

if (null != zipOutputStream) {

try {

zipOutputStream.close();

} catch (IOException e) {

logger.error("", e);

}

}

}

这里我有一个疑问,在new FileOutputStream(zipPath)的过程中如果已经打开了这个文件,但是在new ZipOutputStream过程中出错了,这个时候zipOutputStream并没有创建成功,所以在finally中不会调用close方法,造成的结果就是这个文件不会被关闭。
所以这种关闭方式是不是会有漏洞,还是我的理由有问题?

回答:

这个例子有漏洞,不过漏洞不在这里,而是 FileOutputStream
如果 new ZipOutputStream()调用失败,这个构造方法会抛出运行时异常,而且不会关闭传递进来的 FileOutputStream 对象。
由于调用者也不持有该对象的引用,也无法释放资源,会造成打开的文件描述符没有关闭。
如果使用java8的话可以用 try with,或者在finally块里面释放FileOutputStream 对象持有的资源,这样是比较保险的做法。

回答:

在这个过程中只会发生FileNotFoundException异常,而此时ZipOutputStream对象还没有创建,没有任何流被打开,所以当然是不需要关闭的。所以这段代码没有问题


/**

* @param args

* @throws Exception

*/

public static void main(String[] args) throws Exception {

Test test = new Test();

test.test1();

System.out.println(123);

}

public void test1() {

try {

ArrayList<Double> al = new ArrayList<Double>();

for (int i = 0; i < 1000000; i++) {

for (int j = 0; j < 1000000; j++) {

al.add(Math.random());

}

}

} catch (Throwable e) {

System.out.println("catch");

} finally {

System.out.println("finally");

}

}

输出:

finally

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

at java.lang.Double.valueOf(Unknown Source)

at qmk.TestAnything.test1(TestAnything.java:50)

at qmk.TestAnything.main(TestAnything.java:41)

结论:

发生OutOfMemeoryError时,finally可以执行,但是catchmain方法后面的打印语句都没有执行,虚拟机直接奔溃了。

我之前说发生内存溢出时finally不会执行是不对的,事实表明finally是会执行的,特此更正。

@brayden
图片描述

回答:

解决方法很简单你直接close掉传递的FileOutputStream即可。
这个漏洞是存在的,可以从代码层面解决,这种装饰器模式虽然很好,但是对被装饰的对象管理不当就会出现这种情况。

以上是 关于java中关闭流疑问 的全部内容, 来源链接: utcz.com/p/181731.html

回到顶部