在网上看到一篇关于关闭资源的正确方式: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()方法,还没有经过足够多的实际场景去验证它的性能、鲁棒性

最新文章

  1. SSH框架整合项目(一)——搭建平台和引入依赖
  2. 利用HTML5开发Android(2)---Android中构建HTML5应用
  3. js实现FileUpload选择图片后预览功能
  4. BCTF warmup 50
  5. .NET截断字符串
  6. jquery的动画函数animate()讲解一
  7. Xamarin组件包 Xamarin.ToolKit
  8. 初学Python(一)——数据类型
  9. 问题(一)---线程池,锁、堆栈和Hashmap相关
  10. Linux内存管理 (19)总结内存管理数据结构和API
  11. matlab练习程序(点云下采样)
  12. 安全之路 —— 使用Windows全局钩子打造键盘记录器
  13. 洛谷P1040 加分二叉树【记忆化搜索】
  14. PAT 乙级 1060 爱丁顿数(25) C++版
  15. Postman高级应用——串行传参和动态传参详解
  16. LINQ to Entities does not recognize the method &#39;Int32 ToInt32(System.String)&#39; method, and this method cannot be translated into a store expression
  17. 20165219 Exp1 PC平台逆向破解
  18. java使用simpleDateFormat格式化日期 时间
  19. webpack配置(二)
  20. Centos 部署Cobbler系统

热门文章

  1. 【学习】java下实现调用oracle的存储过程和函数
  2. 路飞学城Python-Day3
  3. GET,POST请求
  4. layer弹窗
  5. Flux架构与Redux简介
  6. 《virtual san 最佳实践》节选 Virtual SAN的发展与现状
  7. HISTFILESIZE与HISTSIZE的区别
  8. [terry笔记]oracle里的执行计划-查看
  9. NYIST 1108 最低的惩罚
  10. UVALive 6084 Happy Camper(数学题)