在网上看到一篇关于关闭资源的正确方式:http://blog.csdn.net/bornforit/article/details/6896775

该博文中的总结:

(1)使用finally块来关闭物理资源(非托管资源),保证关闭操作始终会被执行;

(2)关闭每个资源之前首先保证引用该资源的引用变量不为null;

(3)为每个物理资源使用单独的trycatch块关闭资源,保证关闭资源时引发的异常不会影响其他资源的关闭。

在资源过多的时候,我们要在finally块中写很多的非空判断、以及try-catch块。如果没有关闭非托管资源,比如Connection,即使你给它赋值为null, 它也会常驻内存,必须要手动关闭非托管资源。不管是托管资源还是非托管资源,我们都希望能用相同的方式关闭。为了防止某些时候忘了给资源做非空判断、对每个资源都使用一个try-catch块关闭而导致资源/内存泄漏(), 我们自制一些关闭资源的工具类。而且使用工具类可以减少代码冗余、使代码可读性更好。

下面是我写的工具类:

CloseResources.java

public class CloseResources {
private static final Object[] PARAMS = new Object[0];//使用反射调用方法时传入的参数,可以当作null
private static final ExceptionHandle[] HANDLERS = new ExceptionHandle[0];//空的异常处理器,可以认为是null private static boolean invokeCloseMethod(Object o, Method[] methods) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {//用反射执行无参的close()方法
for (Method method : methods) {
//System.out.println(method.getName());
if (method.getName().equals("close") && method.getParameterTypes().length == 0) {
System.out.println("############调用close() " + o.getClass());
method.invoke(o, PARAMS);
return true;
}
}
return false;
}
public static void close(Object o) {
close(o, null);
}
public static void close(Object o, ExceptionHandle handle) {//ExceptionHandle是我自己定义的
if (o == null) {//如果为空就不调用close()了,免得空指针异常
return;
}
Class<?> clazz = o.getClass();
try {
if (!invokeCloseMethod(o, clazz.getDeclaredMethods())) {//如果重写了close(),就调用重写的
invokeCloseMethod(o, clazz.getMethods());//如果没有重写close(),就调用继承的close()
}
} catch (SecurityException e) {
if (handle != null) {
handle.handleSecurityException(e);
}
} catch (IllegalAccessException e) {
if (handle != null) {
handle.handleIllegalAccessException(e);
}
} catch (IllegalArgumentException e) {
if (handle != null) {
handle.handleIllegalArgumentException(e);
}
} catch (InvocationTargetException e) {
if (handle != null) {
handle.handleInvocationTargetException(e);
}
} catch (Exception e) {
if (handle != null) {
handle.handleException(e);
}
}
}
public static void closeCollection(Collection<?> collection) {//关闭collection,比如List
closeCollection(collection, HANDLERS);
}
public static void closeCollection(Collection<?> collection, ExceptionHandle ... handles) {
if (collection == null) {
return;
}
int i = 0;
for (Object o : collection) {
if (handles == null) {
close(o);
} else if (i < handles.length) {
close(o, handles[i++]);
} else {
close(o);
}
}
collection.clear();
}
public static <K, V> void closeMap(Map<K, V> map) {//关闭map
closeMap(map, HANDLERS);
}
public static <K, V> void closeMap(Map<K, V> map, ExceptionHandle ... handles) {
if (map == null) {
return;
}
Set<K> keys = map.keySet();
int i = 0;
for (K key : keys) {
if (handles == null) {
close(map.get(key));
} else if (i < handles.length) {
close(map.get(key), handles[i++]);
} else {
close(map.get(key));
}
}
map.clear();
}
}

CloseResources工具类的几个方法:

public static void close(Object o):关闭o,不做任何处理
public static void close(Object o, ExceptionHandle handle): 用自定义处理异常的方式关闭o
public static void closeCollection(Collection<?> collection): 关闭collection中的所有资源,并清空collection
public static void closeCollection(Collection<?> collection, ExceptionHandle ... handles): 用自定义异常处理的方式分别关闭collection中的所有资源,并清空collection
putlic static <K, V> void closeMap(Map<K, V> map): 关闭map中的所有资源,并清空map
putlic static <K, V> void closeMap(Map<K, V> map, ExceptionHandle ... handles): 用自定义异常处理的方式分别关闭map中的所有资源,并清空map

如果资源o为null,那么CloseResources的close方法会直接返回,不做处理

使用CloseResources的close方法时还可以传入ExceptionHandle类来接受关闭资源时抛出的异常,并做处理

ExceptionHandle.java

public class ExceptionHandle {
public void handleSecurityException(SecurityException e) {} public void handleIllegalAccessException(IllegalAccessException e) {} public void handleIllegalArgumentException(IllegalArgumentException e) {} public void handleInvocationTargetException(InvocationTargetException e) {} public void handleException(Exception e) {}
}

MyResource.java:

我在close方法中强行抛出IOException,这样方便等会儿使用自定义异常处理的方式关闭资源

public class MyResource implements Closeable {
@Override
public void close() throws IOException {
throw new IOException("调用MyResource的close()时强行抛出IOException");
}
}

主类:

public class Main {
public static void main(String[] args) throws Exception {
BufferedInputStream bis = null;
BufferedOutputStream bos = null; List<Object> list = new ArrayList<Object>();
try {
FileInputStream fis = new FileInputStream("c:/1.txt");
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(new FileOutputStream("c:/2.txt"));
list.add(bis);
list.add(bos);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
CloseResources.closeCollection(list);//可以关闭collection中的资源,并清空collection
CloseResources.close(new MyResource(), new ExceptionHandle() {
@Override
public void handleInvocationTargetException(InvocationTargetException e) {//使用自定义异常处理的方式关闭MyResource
System.out.println("ok");
Throwable t = e.getCause();
t.printStackTrace();
}
});
}
}
}

运行程序的结果:

在主方法中我写了这几句话:

@Override
public void handleInvocationTargetException(InvocationTargetException e) {
System.out.println("ok");
Throwable t = e.getCause();
t.printStackTrace();
}

可以看见,我打印的是InvocationTargetException的Cause,如果直接打印e,会包含InvocationTargetException的信息,实际上我们只需要close()抛出的IOException,因此我先获得Cause。如果不想用这种方式,而是直接把Cause: IOException传到handleException,不分出那么多的自定义异常处理方法,可以自己修改一下代码。在实际场景,不应该仅仅只调用printStackTrace(),而是把异常写入日志、尝试修复异常、做一些业务。

应该指出:这个工具类还很不完善,例如,只能执行资源无参的close()方法,还没有经过足够多的实际场景去验证它的性能、鲁棒性

java关闭资源,自制关闭资源工具类的更多相关文章

  1. java里poi操作excel的工具类(兼容各版本)

    转: java里poi操作excel的工具类(兼容各版本) 下面是文件内具体内容,文件下载: import java.io.FileNotFoundException; import java.io. ...

  2. Java判断不为空的工具类总结

    1.Java判断是否为空的工具类,可以直接使用.包含,String字符串,数组,集合等等. package com.bie.util; import java.util.Collection; imp ...

  3. Java字符串转16 进制工具类Hex.java

    Java字符串转16 进制工具类Hex.java 学习了:https://blog.csdn.net/jia635/article/details/56678086 package com.strin ...

  4. Java中的AES加解密工具类:AESUtils

    本人手写已测试,大家可以参考使用 package com.mirana.frame.utils.encrypt; import com.mirana.frame.constants.SysConsta ...

  5. java.util.Arrays----操作数组的工具类

    java.util.Arrays操作数组的工具类,里面定义了很多操作数组的方法 1.boolean equals(int[] a,int[] b):判断两个数组是否相等. 2.String toStr ...

  6. Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger

    在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...

  7. Java学习笔记49(DBUtils工具类二)

    上一篇文章是我们自己模拟的DBUtils工具类,其实有开发好的工具类 这里使用commons-dbutils-1.6.jar 事务的简单介绍: 在数据库中应用事务处理案例:转账案例 张三和李四都有有自 ...

  8. Java学习笔记48(DBUtils工具类一)

    上一篇的例子可以明显看出,在增删改查的时候,很多的代码都是重复的, 那么,是否可以将增删改查封装成一个类,方便使用者 package demo; /* * 实现JDBC的工具类 * 定义方法,直接返回 ...

  9. java分页的实现(后台工具类和前台jsp页面)

    1.首先,新建一个类Page.java public class Page implements Serializable { private static final long serialVers ...

  10. Java并发之Semaphore和Exchanger工具类简单介绍

    一.Semaphore介绍 Semaphore意思为信号量,是用来控制同时访问特定资源的线程数数量.它的本质上其实也是一个共享锁.Semaphore可以用于做流量控制,特别是公用资源有限的应用场景.例 ...

随机推荐

  1. 快速傅里叶变换(Fast-Fourier Transform,FFT)

    数学定义: (详细参考:https://www.baidu.com/link?url=oYAuG2o-pia_U3DlF5n_MJZyE5YKfaVRUHTTDbM1FwM_kDTjGCxKpw_Pb ...

  2. 在vue组件中style scoped中遇到的坑

    在uve组件中我们我们经常需要给style添加scoped来使得当前样式只作用于当前组件的节点.添加scoped之后,实际上vue在背后做的工作是将当前组件的节点添加一个像data-v-1233这样唯 ...

  3. FCC编程题之中级算法篇(中)

    介绍 接着上次的中级算法题 目录 1. Missing letters 2. Boo who 3. Sorted Union 4. Convert HTML Entities 5. Spinal Ta ...

  4. python对比图片

    通过python的PIL模块可以对比两张图片是否相同,具体源码如下 from PIL import Image from PIL import ImageChops def compare_image ...

  5. MATLAB曲线拟合

    转自原文 MATLAB曲线拟合 曲线拟合 实例:温度曲线问题 气象部门观测到一天某些时刻的温度变化数据为: t 0 1 2 3 4 5 6 7 8 9 10 T 13 15 17 14 16 19 2 ...

  6. Android 之 Eclipse没法生成R文件

    这几天被Eclipse整哭了.也怪自己手贱把appcompat_v7给删了. Eclipse创建project假设是兼容4.0下面,会多生成一个projectappcompat_v7,例如以下图: 这 ...

  7. Dynamics CRM2013 Form利用window.location.reload()进行全局刷新带来的问题及解决的方法

    CRM2013以后.表单的保存后变成了局部刷新而非全局刷新,但非常多情况下我们须要刷新整个页面.通过刷新页面来使脚本运行或者业务规则运行来实现某些业务效果,一般我们会使用window.location ...

  8. TOMCATserver不写port号、不写项目名訪问项目、虚拟文件夹配置

    一.不写port. 这个问题都被问烂了.由于TOMCAT默认的訪问port为8080.而TCP/IP协议默认80port訪问,大家之所以看到别的站点都不写port号是由于人家用的的80port訪问的, ...

  9. 又见关系并查集 以POJ 1182 食物链为例

    简单的关系并查集一般非常easy依据给出的关系搞出一个有向的环,那么两者之间的关系就变成了两者之间的距离. 对于此题: 若u.v不在一个集合内,则显然此条语句会合法(暂且忽略后两条.下同). 那么将f ...

  10. 怎样在Ubuntu手机平台中开发Cordova HTML5应用

    我们知道Cordova HTML5应用具有夸平台的特性,同一时候也具有訪问本地一些资源的能力.在今天的这篇文章中.我们将介绍一下怎样创建并执行一个Cordova HTML5的应用到我们的Ubuntu手 ...