java关闭资源,自制关闭资源工具类

在网上看到一篇关于关闭资源的正确方式: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中的所有资源,并清空collectionputlic 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关闭资源,自制关闭资源工具类

时间: 2024-08-10 17:04:00

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

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

原文:Java字符串转16 进制工具类Hex.java 源代码下载地址:http://www.zuidaima.com/share/1550463378410496.htm Java 字符串转 16 进制工具类 Hex.java 实现 16进制 0xfecd .. 和 java 字符串之间的互转换! 如果做开发,通常用户登陆密码都会 mad5(salt + pwd) 然后再将 md 之后的数据 hex 一下. 这个工具类,就是实现此效果的. /* * */ package com.zuidaim

自制MVC之工具类插件一

1).BreakRomoteURLAttribute 提交或交互的URL数据是否来源于其它地方,站内提交,防止跨站 2). DataAttribute 取得post或get提交的数据.如果没有特殊设置,取得的数据是sql注入.xss注入过滤的. 属性名 作用 默认值 选项说明 其它说明 IsEmpty 是否可以提交空数据,就是表单数值一个都没有的情况. true 必填 AspectPriority 插件执行优先级 空 可选 MD5Key 需md5加密的key,多个用逗号分隔. 10000 可选

JAVA对象任意深度克隆clone工具类分享

原文:JAVA对象任意深度克隆clone工具类分享 源代码下载地址:http://www.zuidaima.com/share/1550463408114688.htm package com.zuidaima.n_app.util; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import jav

Java导出防止小数显示不全工具类

1.说明 在做项目的过程中,发现导出功能中的数据显示不全,如"0.4",会显示成".4":"-0.8"会显示成"-.8" 现在,通过以下Java工具类保证导出的数据(特别是小数)显示全 2.Java工具类 /** * @Title:DecimalPoint.java * @Package:com.you.model * @Description:解决导出时小数前的"0"被去掉的问题 * @Author: 游

Java获取时间 时间计算 转换时间工具类

Java获取时间 时间计算 转换时间工具类 JAVA日期工具类 package com.mh.util; import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; /** * 时间日期转换工具类 */ public class DateTimeUtil { /** *

java读写文件(可当工具类保存。解决乱码)

//读文件 public static String ReadFile(String path) { File file = new File(path); BufferedReader reader = null; String laststr = ""; try { reader = new BufferedReader(new FileReader(file)); String tempString = null; while ((tempString = reader.read

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

1.首先,新建一个类Page.java 1 public class Page implements Serializable { 2 private static final long serialVersionUID = -3198048449643774660L; 3 private int pageNow = 1; // 当前页数 4 private int pageSize = 10; // 每页显示记录的条数 5 private int totalCount; // 总记录条数 6

Java.util.zip 压缩与解压缩工具类

Java.util.zip 提供用于读写标准 ZIP 和 GZIP 文件格式的类. 还包括使用 DEFLATE 压缩算法(用于 ZIP 和 GZIP 文件格式)对数据进行压缩和解压缩的类. 依赖 Jdk 编写该工具类,不依赖任何第三方 jar,随用随取,实现功能大体如下: 1.目录级别递归压缩与解压缩 zip: 2.单文件压缩和解压缩 zip : import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipIn

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

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

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

上一篇文章是我们自己模拟的DBUtils工具类,其实有开发好的工具类 这里使用commons-dbutils-1.6.jar 事务的简单介绍: 在数据库中应用事务处理案例:转账案例 张三和李四都有有自己的存款 主键 帐户名 余额 1 张三 1000 2 李四 10 要从张三的账户余额中转账800到李四账户 SQL语句实现: update xx set 余额 = 余额-800 where 主键=1 update xx set 余额 = 余额+800 where 主键=2 虽然操作成功,但是会出现问