美文网首页
Java异常整理及日志log学习

Java异常整理及日志log学习

作者: Loon1993 | 来源:发表于2018-11-22 14:47 被阅读0次

一、异常

www:what why how

  • What

    1. 定义:《Java编程思想》:异常情形(Exception condition)是指阻止当前方法或作用域继续执行的问题。把异常情形与普通问题区分很重要,普通问题是指,在当前环境下能得到足够的信息,总能处理这个错误。异常情形,就不能继续下去,因为当前环境下无法获得必要的信息来解决问题。需要从当前环境退出,并且把问题抛给上一级环境。

    例如:当进行除法运算,被除数等于0的情况,作为一种非法输入,需要抛出异常。

    public class Calculator {
        public int devide(int num1, int num2) {
            if(num2 == 0) {
                throw new IllegalArgumentException("除数不能为零");
            }
            return num1/num2;
        }
    }
    
    1. 异常的基本体系:
    image
    • Throwable ,作为所有异常与错误的超类,类似定义一切都可抛的东西,其中具有两个子类,ErrorException
    • Error,用于指示合理的应用程序不应该试图捕获的严重问题。遇到Error,说明出现的错误以及不是代码层面的问题了,建议谷歌。
    • Exception,它指出了合理的应用程序想要捕获的条件。Exception又分为两类:一种是CheckedException,一种是UncheckedException。这两种Exception的区别主要是CheckedException需要用try...catch...显示的捕获,而UncheckedException不需要捕获。通常UncheckedException又叫做RuntimeException。《effective java》指出:对于可恢复的条件使用被检查的异常(CheckedException),对于程序错误(言外之意不可恢复,大错已经酿成)使用运行时异常(RuntimeException)。
  • Why

    • 异常处理机制作用

      1. 告警

      2. 方便问题的排查

      3. 避免出现的异常问题影响下面的代码运行

      4. 针对出现的异常情况,进行捕获,以及可以做相应的恢复处理

      5. 自定义异常,符合面向对象思想,处理业务异常

    • 自定义异常

      public class NormandyCheckedException extends Exception {
          //异常传递cause
          public NormandyCheckedException(String message, Throwable cause) {
              super(message, cause);
          }
      }
      
      1. 表示与业务相关的问题
      2. 告知调用方需要在开发过程中考虑部分的逻辑
      3. 需要记录异常发生的栈信息以及message
  • How

    1. 异常的通常处理手段

      • 对代码块用try..catch进行异常捕获处理;

      • 在 该代码的方法体外用throws进行抛出声明,你需要谨慎处理。下游方在调用你的方法时,需要针对你抛出的异常进行处理。

        此时有两种情况:

        • Exception及子类 必须手动 catch 或者 throws

        • RuntimeExcption及子类 可以选择忽略

      • 在代码块用throw手动抛出一个异常对象,此时也有两种情况,跟2)中的类似:

        • 如果抛出的异常对象是Exception,此方法的调用者必须显示地用try..catch块进行捕获或者继续向上层抛出异常。
        • 如果抛出的异常对象是运行时异常,此方法的调用者可以选择地进行异常捕获处理。
        • 如果最终将异常抛给main方法,则相当于交给jvm自动处理,jvm会简单地打印异常信息
  1. Try catch

    • 先catch子类Exception 若父类Exception在子类之前会覆盖

    • 尽量进行小范围的try catch

    • 尽量避免用Exception捕获异常,其会捕获受检异常与非受检异常


    • catch异常之后需要打印出堆栈信息(切记不能重复打印)

    • 不能存在空catch块

    • 不要捕获Error(RuntimeException)

    • 尽量在高层进行异常的捕获操作

    • 避免异常丢失(见代码)

  2. throw/throws

    throw:在方法内部主动抛出异常

    throws:当方法中存在未catch的受检异常,需要在方法签名后面抛出

    • 当捕获到异常之后,希望在下一级调用中处理,可以通过throw
    • 异常传递:传递 cause 或者调用initCause方法
    • catch块中throw出Exception,就不需要进行log日志记录,避免重复记录了异常记录
    • 异常限制:在类继承的时候,方法覆盖时进行异常抛出声明,子类可以不抛出异常或则只能抛出父类的异常或其子类异常
    • 尽量不要用异常作为控制流程的方式,带来额外的消耗
  3. finally

    • 跟随在try 之后,在方法返回之前必然执行finally
    • 一般在finally中进行资源的close操作
  4. try with resource(一定需要了解资源的close方法内部的实现逻辑。否则还是可能会导致资源泄露。)

    public class Demo {
        public static void main(String[] args) {
            BufferedInputStream bin = null;
            BufferedOutputStream bout = null;
            try {
                bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
                bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")));
                int b;
                while ((b = bin.read()) != -1) {
                    bout.write(b);
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            finally {
                if (bin != null) {
                    try {
                        bin.close();
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                    finally {
                        if (bout != null) {
                            try {
                                bout.close();
                            }
                            catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    }
    
    image
public class TryWithResource {
    public static void main(String[] args) {
        try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
             BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
            int b;
            while ((b = bin.read()) != -1) {
                bout.write(b);
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 总 结

  1. 使用异常一般是内部系统调用,包括rpc调用方式。但是针对外部调用时,可以使用约定的code表示,而不应直接抛异常。
  2. 针对可恢复的情况使用受检异常,针对编程错误使用runtime exception
  3. 优先使用java提供的标准异常
  4. 抛出异常的方法,可以加上javaDoc 的@throw标记说明
  5. 当产生异常情况下,尽量使整体方法执行保持原子性
  6. 不要忽略异常:不要使用空catch块

思考

到处都是try catch 是好是坏?

二、日志

www:what why how

  • What

    日志文件是用于记录系统操作事件的记录文件或文件集合,可分为事件日志和消息日志。具有处理历史数据、诊断问题的追踪以及理解系统的活动等重要作用。

  • Why

    1. 便于定位问题
    2. 观察分支是否执行
    3. 观察主流程是否成功运行
  • How

    1. 日志的级别

      • Trace:特别详细的系统运行完成信息,业务代码中,建议不要使用
      • Debug:针对开发测试环节中,打印需要测试的流程信息(线上一般需要关闭debug级别的日志)
      • Info: 系正常运行信息
      • **Warn: **不应该出现但是不影响程序、当前请求正常运行的异常情况
      • **Error: **影响到程序正常运行、当前请求正常运行的异常情况
    2. 打日志的方式

      • 必须使用参数化信息的方式

      • 如有参数变量,使用[]隔离。分隔符用统一分隔符,便于统计(详情,@青华) "[]"的正则问题

        logger.debug("Processing trade_with_id_:[{}] and symbol : [{}] ", id, symbol);
        
      • 不要进行字符串拼接,那样会产生很多String对象,占用空间,影响性能。
        反例:

        logger.debug("Processing trade with id: " + id + " symbol: " + symbol);
        
      • 尽量打印日志的上下文(如if 分支),方便定位运行的流程 [远程调试方法]

      • 遵循TraceId的原则,可以根据某个id在日志中体现出整体运行流程

      • 如果日志中需要打印对象信息,尽量重新toString() 方法 或着 只打印对象的部分字段(id、no等关键信息)

        log.info("user credit material uid:{}, materialInfo:{}", uid, JSON.toJSONString(materialApplyInfo));
        
      • 遇到异常,在catch中需要记录,但避免重复记录

        try{
            doService(int id);
        }catch(Exception e) {
            log.error("Service Exception...,id:[{}]", id, ex);
            throw e;
        }
        
      • 避免出现用户的隐私内容,用uid等代替用户信息

      • 调用外部接口,打印出来入参与出参

Code Review

  1. 使用exception,保持处理流程的原子性。

  2. 通过log.error记录日志,并且进行数据统计。

  3. 在对外输出的时候,只是通过OpenResponse进行反馈,实现封装性。

  4. 在log 日志中,没有记录对应aid 或者能代表出问题的订单。算是无效的日志。

  5. 在遇到某些业务异常,可以直接return,但是通过 catch Exception 可能会 捕获到其他异常。

相关文章

  • Java异常整理及日志log学习

    一、异常 www:what why how What定义:《Java编程思想》:异常情形(Exception co...

  • 2018-01-14 Java应用日志

    java日志体系 java日志体系很混乱。在日志实现框架在有log4j,log4j2,java.util.log,...

  • Java日志体系整体梳理

    一、Java日志体系的发展历程 Log4j:在JDK 1.3及以前,Java打日志依赖System.out.pri...

  • Netty源码分析-08 Netty的日志

    8.1 Java的日志系统 java领域存在多种日志框架,目前常用的日志框架包括Log4j,Log4j 2,Com...

  • 清理linux日志 持续更新

    常见的日志文件如下: nginx log日志 java的进程的输出 /var/log/journal/ 清理未清理...

  • tomcat日志详解

    /logs catalina.日期.log--启动日志 localhost.2018-07-24.log--异常日...

  • Java日志框架JUL

    1 日志实现原理 Java 的日志框架有很多,比如:JUL(Java Util Logging)、Log4j、Lo...

  • Java日志:Log4j

    为啥叫Log4j? Log4j就是log for java。是针对Java语言输出日志的工具,够见名知意吧? Lo...

  • 无标题文章

    Java日志处理问题? Java中日志处理,用了druid和log4j处理日志,druid对项目进行监控,通过lo...

  • Java日志系统的总结

    日志系统归类以及关系 常用的日志框架: slf4j、logback 、log4j、log4j2、JUL(java ...

网友评论

      本文标题:Java异常整理及日志log学习

      本文链接:https://www.haomeiwen.com/subject/gaelqqtx.html