博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java关闭资源,自制关闭资源工具类
阅读量:5316 次
发布时间:2019-06-14

本文共 6666 字,大约阅读时间需要 22 分钟。

在网上看到一篇关于关闭资源的正确方式:

 

该博文中的总结:

(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
void closeMap(Map
map) {
//关闭map closeMap(map, HANDLERS); } public static
void closeMap(Map
map, ExceptionHandle ... handles) { if (map == null) { return; } Set
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): 用自定义处理异常的方式关闭opublic static void closeCollection(Collection
collection): 关闭collection中的所有资源,并清空collectionpublic static void closeCollection(Collection
collection, ExceptionHandle ... handles): 用自定义异常处理的方式分别关闭collection中的所有资源,并清空collection putlic static
void closeMap(Map
map): 关闭map中的所有资源,并清空mapputlic static
void closeMap(Map
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 list = new ArrayList();         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(); } }); } } }

 

运行程序的结果:

 

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

@Overridepublic 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()方法,还没有经过足够多的实际场景去验证它的性能、鲁棒性

 

转载于:https://www.cnblogs.com/lanhj/p/3881486.html

你可能感兴趣的文章
【Crash Course Psychology】2. Research & Experimentation笔记
查看>>
两数和
查看>>
移动设备和SharePoint 2013 - 第3部分:推送通知
查看>>
SOPC Builder中SystemID
查看>>
MySQL数据库备份工具mysqldump的使用(转)
查看>>
NTP服务器配置
查看>>
【转】OO无双的blocking/non-blocking执行时刻
查看>>
ul li剧中对齐
查看>>
关于 linux 的 limit 的设置
查看>>
HDU(4528),BFS,2013腾讯编程马拉松初赛第五场(3月25日)
查看>>
vim中文帮助教程
查看>>
MySQL基础3
查看>>
云计算数据与信息安全防护
查看>>
全局设置导航栏
查看>>
RxJS & Angular
查看>>
面向对象(多异常的声明与处理)
查看>>
MTK笔记
查看>>
ERROR: duplicate key value violates unique constraint "xxx"
查看>>
激活office 365 的启动文件
查看>>
无法根据中文查找
查看>>