关于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");
}
}
输出:
finallyException 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
可以执行,但是catch
和main
方法后面的打印语句都没有执行,虚拟机直接奔溃了。
我之前说发生内存溢出时finally不会执行是不对的,事实表明finally是会执行的,特此更正。
回答:
解决方法很简单你直接close掉传递的FileOutputStream即可。
这个漏洞是存在的,可以从代码层面解决,这种装饰器模式虽然很好,但是对被装饰的对象管理不当就会出现这种情况。
以上是 关于java中关闭流疑问 的全部内容, 来源链接: utcz.com/p/181731.html