浅谈在java程序中自定义异常处理

18 篇文章 0 订阅

浅谈在java程序中如何拦截全局异常

一.原生java 如何拦截?

1. 简单的异常示例

这是一段最简单的异常代码

  public static void  main(String[] args){
       System.out.println(1/0);
    }

如果正常的执行这段代码, 那么控制台可能只有简单的错误输出
在这里插入图片描述

2.如何改变的原生的输出呢

使用 Thread.setDefaultUncaughtExceptionHandler 设置自定义的全局异常

比如下方例子:

 private static class JavaExceptionHandler {
    public static void handler() {
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable e) {
                Console.error("java handle this error!,reason:{},happen in thread:[{}], ", e.getMessage(), t.getName());
            }
        });
    }
}

那么在执行1/0之前使用 JavaExceptionHandler.handler(),那么输出的信息则被自定义处理
在这里插入图片描述

3. 那么自定义异常有什么用

可以在程序崩溃时, 调用消息API 进行通知, 调用数据库API进行存储 等等

  Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        public void uncaughtException(Thread t, Throwable e) {
           // TODO  记录程序崩溃的时间及异常信息
        }
    });
4. setDefaultUncaughtExceptionHandler 不可以阻止程序退出

当运行的代码在不想发生异常时错误退出的话, 应该尽可能使用try catch 处理自己的代码,那么程序就可以从始至终的运行.
setDefaultUncaughtExceptionHandler相当于在崩溃前,做最后的一些事情
因为异常发生时在主线程main上, 所以已经不能阻止jvm 退出了 .
所以不应该在setDefaultUncaughtExceptionHandler尝试写一些调用系统api 重启的操作.

二. spring中如何拦截?

1. spring中的简单异常示例

这是一个简单的示例组件, 当调用该组件时, 会爆出IndexOutOfBoundsException 异常

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.scan("cn.note");
        ctx.refresh();
        ctx.getBean(AopErrorTest.class).execute();
    }

    @Component
    public static class AopErrorTest {
        public void execute() {
            Console.log(new ArrayList<>().get(0));
        }

    }
2. 如何拦截spring的异常呢?

可以使用spring 的aop插件,在方法执行时拦截


    @Component
    @Aspect
    @EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
    public static class AopErrorHandler {
        @Pointcut("execution(* cn.note..*.*(..))")
        public void pointcut() {
        }

        /**
         * 切面日志拦截
         */
        @Around("pointcut()")
        public Object handle(ProceedingJoinPoint joinPoint) {
            Object result = null;
            try {
                result = joinPoint.proceed();
            } catch (Throwable error) {
                Console.error("AOP handle this error! reason:{},happen in thread:[{}]", error.getMessage(), Thread.currentThread().getName());
            }
            return result;
        }
    }

当实现AOP的异常拦截器后, 当业务方法发生异常时, 可以被统一的进行错误处理 ,可以在catch 中使用自定义的方法进行错误的处理.

因为异常被catch 进行的错误处理, 所以并没有影响main主进程的执行逻辑, 所以如果不主动调用System.exit 那么业务会按照之前预料的顺序执行 ,

但是可能因为被catch 时,影响了方法本应产生的结果, 所以AOP拦截异常后,也应该从正常的逻辑顺序中中断. 所以可以细细回味springboot中的异常拦截中有@ControllerAdvice
在这里插入图片描述

3. 在此回想springboot 的@ControllerAdvice 与@ExceptionHandler

为什么使用@ControllerAdvice 注解可以拦截web服务异常

@ControllerAdvice
public class SpringControllerAdvice {
    @ExceptionHandler(RuntimeException .class)
    public ModelAndView runtimeExceptionHandler(RuntimeException e) {
        return new ModelAndView("error");
    }
}

三. swing GUI中如何拦截?

1. swing中的简单异常代码
   button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    String str = null;
                    Console.log("NullException ...", str.length());
                }
            });

运行这段代码,当按钮点击error 按钮时, 控制台会输出空指针错误
在这里插入图片描述

2. 如何改变原生的输出呢?

当在开发过程中, 你可能更直观的想点击error时,弹出一个alert消息告诉自己那里出错了, 在swing中需要使用 Toolkit.getDefaultToolkit().getSystemEventQueue() 在处理事件分发时进行自定义处理
如SwingExceptionHandler ,自定义EventQueue ,重写dispatchEvent 事件:

    private static class SwingExceptionHandler {

        /**
         * 自定义事件分发
         */
        private static class EventQueueProxy extends EventQueue {
            protected void dispatchEvent(AWTEvent newEvent) {
                try {
                    super.dispatchEvent(newEvent);
                } catch (Throwable t) {
                    String errorMsg = StrUtil.format("swing handle this error!,reason:{},happen in thread:[{}] ", t.getMessage(), Thread.currentThread().getName());
                    Console.error(errorMsg);
                    WinUtil.alert(errorMsg);
                }
            }
        }

        public static void handler() {
            Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueueProxy());
        }
    }

在运行swing前使用 SwingExceptionHandler.handler(), 那么就可以在点击error时, 可以感知到代码出错了

   public static void main(String[] args) {
        CoreFlatLaf.install();
        SwingExceptionHandler.handler();
        FrameUtil.launchTest(new SwingErrorDemo());
    }

运行效果如图:
在这里插入图片描述

总结

自定义异常应该用作记录, 回溯时排查的一种手段, 而不应该成为程序逃避bug的的一种捷径.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值