• 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中的所有资源,并清空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()方法,还没有经过足够多的实际场景去验证它的性能、鲁棒性

  • 相关阅读:
    PHP操作二进制字节数据
    Linux端口转发-rinted工具部署、配置、使用
    Netty学习(八)-Netty的心跳机制
    Navicat Premium 12破解方法
    App界面设计规范-字体规范
    PHP 扩展开发之Zephir
    rinetd 一个linux下的端口转发工具
    windows node版本管理工具nvm
    vue cli 常见问题汇总
    监听微信返回
  • 原文地址:https://www.cnblogs.com/lanhj/p/3881486.html
Copyright © 2020-2023  润新知