7. 异常、断言及日志

1.异常

1).什么是异常

异常,就是不正常的意思。指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。
注意:异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行.

2).异常体系

异常机制其实是帮助我们找到程序中的问题,异常的根类是 java.lang.Throwable ,其下有两个子类:java.lang.Error 与 java.lang.Exception ,平常所说的异常指 java.lang.Exception 。
在这里插入图片描述

Throwable体系:
Error:严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。
Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。好比感冒、阑尾炎。
Throwable中的常用方法:
public void printStackTrace() :打印异常的详细信息。包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。
public String getMessage() :获取发生异常的原因。提示给用户的时候,就提示错误原因。
public String toString() :获取异常的类型和异常描述信息(不用)。

3).异常分类

我们平常说的异常就是指Exception,因为这类异常一旦出现,我们就要对代码进行更正,修复程序。
异常(Exception)的分类:根据在编译时期还是运行时期去检查异常?
编译时期异常:checked异常。在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常);
运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)。
在这里插入图片描述

在这里插入图片描述

4).异常处理

①抛出异常throw
在java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。那么,抛出一个异常具体如何操作呢?

  1. 创建一个异常对象。封装一些提示信息(信息可以自己编写)。
  2. 需要将这个异常对象告知给调用者。怎么告知呢?怎么将这个异常对象传递到调用者处呢?通过关键字throw就可以完成。throw 异常对象。throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
    代码演示:
public class ThrowDemo {
    public static void main(String[] args) {
        //创建一个数组
        int[] arr = {2,4,52,2};
        //根据索引找对应的元素
        int index = 4;
        int element = getElement(arr, index);
        System.out.println(element);
        System.out.println("over");
    }
    /*
     * 根据 索引找到数组中对应的元素
     */
    public static int getElement(int[] arr,int index){
       //判断  索引是否越界 
        if(index<0 || index>arr.length‐1){
             /*
             判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
             这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。
              */
             throw new ArrayIndexOutOfBoundsException("哥们,角标越界了~~~");
        }
        int element = arr[index];
        return element;
    }
}

如果产生了问题,我们就会throw将问题描述类即异常进行抛出,也就是将问题返回给该方法的调用者。
那么对于调用者来说,该怎么处理呢?一种是进行捕获处理,另一种就是继续讲问题声明出去,使用throws声明处理。
②声明异常throws
声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲解该方式),那么必须通过throws进行声明,让调用者去处理。
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
声明异常格式: 修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }
代码演示:

public class ThrowsDemo2 {
    public static void main(String[] args) throws IOException {
        read("a.txt");
    }
    public static void read(String path)throws FileNotFoundException, IOException {
        if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
            // 我假设  如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常  throw
            throw new FileNotFoundException("文件不存在");
        }
        if (!path.equals("b.txt")) {
            throw new IOException();
        }
    }
}

③捕获异常try…catch
捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。
捕获异常语法如下:

try{
     //编写可能会出现异常的代码
}catch(异常类型  e){
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}

代码演示:

public class TryCatchDemo {
    public static void main(String[] args) {
        try {// 当产生异常时,必须有处理方式。要么捕获,要么声明。
            read("b.txt");
        } catch (FileNotFoundException e) {// 括号中需要定义什么呢?
           //try中抛出的是什么异常,在括号中就定义什么异常类型  
            System.out.println(e);
        }
        System.out.println("over");
    }
    /*
     *
     * 我们 当前的这个方法中 有异常  有编译期异常
     */
    public static void read(String path) throws FileNotFoundException {
        if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
            // 我假设  如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常  throw
            throw new FileNotFoundException("文件不存在");
        }
    }
}

④多个异常捕获

try{
     //编写可能会出现异常的代码
}catch(异常类型A  e){  当try中出现A类型异常,就用该catch来捕获.
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}catch(异常类型B  e){  当try中出现B类型异常,就用该catch来捕获.
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}

多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。
⑤finally 代码块
finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。finally不能单独使用,必须和try配套使用。
只有在try或者catch中调用退出JVM的相关方法时,finally才不会执行,否则finally绝对会执行。

5).自定义异常
  1. 自定义一个编译期异常: 自定义类 并继承于 java.lang.Exception 。
  2. 自定义一个运行时期的异常类:自定义类 并继承于 java.lang.RuntimeException 。
    演示:
// 业务逻辑异常
public class LoginException extends Exception {
    /**
     * 空参构造
     */
    public LoginException() {
    }
    /**
     *
     * @param message 表示异常提示
     */
    public LoginException(String message) {
        super(message);
    }
}
public class Demo {
    // 模拟数据库中已存在账号
    private static String[] names = {"bill","hill","jill"};
  
    public static void main(String[] args) {    
        //调用方法
        try{
              // 可能出现异常的代码
            checkUsername("nill");
            System.out.println("注册成功");//如果没有异常就是注册成功
        }catch(LoginException e){
            //处理异常
            e.printStackTrace();
        }
    }
    //判断当前注册账号是否存在
    //因为是编译期异常,又想调用者去处理 所以声明该异常
    public static boolean checkUsername(String uname) throws LoginException{
        for (String name : names) {
            if(name.equals(uname)){//如果名字在这里面 就抛出登陆异常
                throw new LoginException("亲"+name+"已经被注册了!");
            }
        }
        return true;
    }
}

2.断言

1).断言概述

编写代码时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设。可以将断言看作是异常处理的一种高级形式。断言表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真。

2).断言使用格式
  • 1.assert 布尔表达式
  • 2.assert 布尔表达式:消息
    使用第一种格式,当布尔类型表达式为false时,抛出AssertionError异常;如果是第二种格式,则输出错误消息。
public class Test {
    public static void main(String[] args) {
        boolean isOk = 1 > 2;
        //assert isOk;
        assert isOk:"1不该大于2";
        System.out.println("程序正常");
    }
}
3).断言的启用

在默认情况下,断言不起作用,在idea等工具中可以开启和关闭断言功能。
Run→Edit Configrations
在这里插入图片描述

在VM栏里输入-ea开启断言,输入-da关闭断言。
在这里插入图片描述

3 日志Logger

3.1 Logger

在Java中实现日志记录的方式有很多种,其中最简单的方式,就是System.out.print,System.err.print 这样直接在控制台打印消息了。接下来我们介绍的:java.util.logging.Logger是在JDK 1.4 版本之后加入的,提供了日志记录的API ,可以往控制台/文件中写日志了。
Logger 对象用来记录特定系统或应用程序组件的日志消息。一般使用圆点分隔的层次名称空间来命名 Logger。Logger 名称可以是任意的字符串,但是它们一般应该基于被记录组件的包名或类名,如 java.net 或 javax.swing。此外,可以创建“匿名”的 Logger,其名称未存储在 Logger 名称空间中。
可通过调用某个 getLogger 工厂方法来获得 Logger 对象。这些方法要么创建一个新 Logger,要么返回一个合适的现有 Logger。
日志消息被转发到已注册的 Handler 对象,该对象可以将消息转发到各种目的地,包括控制台、文件、OS 日志等等。

3.2 创建Logger对象

static Logger getLogger(String name) 为指定子系统查找或创建一个 logger。
Logger logger1 = Logger.getLogger(“com.suncaper.lxp.LogDemo”);
注意:name是Logger的名称,当名称相同时候,同一个名称的Logger只创建一个。

3.3 Logger的级别

在这里插入图片描述

logger默认的级别是INFO,比INFO更低的日志将不显示。
Logger的默认级别定义是在jre安装目录的lib下面的logging.properties。
可通过setLevel(Level.FINEST)方法改变级别。

public class Test {
    public static void main(String[] args) throws IOException {
        Logger log = Logger.getLogger("com");
        log.setLevel(Level.FINEST);
    }
}

3.4 Handler

Handler 对象从 Logger 中获取日志信息,并将这些信息导出。例如,它可将这些信息写入控制台或文件中,也可以将这些信息发送到网络日志服务中,或将其转发到操作系统日志中。可通过执行 setLevel(Level.OFF) 来禁用 Handler,并可通过执行适当级别的 setLevel 来重新启用。

//将日志打印至控制台
public class Test {
    public static void main(String[] args) throws IOException {
        Logger logger = Logger.getLogger("com.suncaper.test.LogDemo");
        logger.setLevel(Level.ALL);

        ConsoleHandler consoleHandler = new ConsoleHandler();
        consoleHandler.setLevel(Level.FINEST);
        logger.addHandler(consoleHandler);

        logger.severe("严重");
        logger.warning("警告");
        logger.info("信息");
        logger.config("配置");
        logger.fine("良好");
        logger.finer("较好");
        logger.finest("最好");
    }
}
//将日志写入文本
public class Test {
    public static void main(String[] args) throws IOException {
        Logger log = Logger.getLogger("com");
        log.setLevel(Level.INFO);
        Logger log1 = Logger.getLogger("com.suncaper");
        ConsoleHandler consoleHandler =new ConsoleHandler();
        consoleHandler.setLevel(Level.ALL);
        log.addHandler(consoleHandler);
        FileHandler fileHandler = new FileHandler("d://testlog.log");
        fileHandler.setLevel(Level.INFO);
        log.addHandler(fileHandler);
        log.info("111");
        log1.info("222");
        log1.fine("333");
    }
}

默认的日志方式是xml格式,很烂。所以最好自定义下logger的格式。需要用Formatter来定义。

3.5 Formatter

Formatter 为格式化 LogRecords 提供支持。
一般来说,每个日志记录 Handler 都有关联的 Formatter。Formatter 接受 LogRecord,并将它转换为一个字符串。默认设置即为:fileHandler.setFormatter(new XMLFormatter());可通过fileHandler.setFormatter(new SimpleFormatter())来修改日志记录的信息。

//将日志格式化写入文本
public class Test {
    public static void main(String[] args) throws IOException {
        Logger log = Logger.getLogger("com");
        log.setLevel(Level.INFO);
        Logger log1 = Logger.getLogger("com.suncaper");
        ConsoleHandler consoleHandler =new ConsoleHandler();
        consoleHandler.setLevel(Level.ALL);
        log.addHandler(consoleHandler);
        FileHandler fileHandler = new FileHandler("d://testlog.log");
		fileHandler.setFormatter(new SimpleFormatter());
        fileHandler.setLevel(Level.INFO);
        log.addHandler(fileHandler);
        log.info("111");
        log1.info("222");
        log1.fine("333");
    }
}
  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我超爱写bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值