Java高级--异常

1.程序中的异常

public class TestException {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入被除数:");
        int num1 = input.nextInt();
        System.out.println("请输入除数:");
        int num2 = input.nextInt();
        System.out.println(String.format("%d / %d = %d", num1, num2, num1 / num2));
​
        //java.lang.ArithmeticException
        //java.util.InputMismatchException
    }
}
  • 输入正常,程序正常执行完成

  • 当除数输入0:java.lang.ArithmeticException,计算异常

  • 当除数输入a:java.util.InputMismatchException,输入不匹配异常

  • 在程序的运行过程中,可能会出现一些问题,最终导致jvm非正常停止,我们称之为运行时异常

2.异常的处理

  1. 通过自己写if-else代码判断异常情况

    • 代码臃肿

    • 会花费很多的精力考虑异常情况

    • 很难考虑到所有的异常

  2. 通过Java的异常处理机制,也就是由java系统来堵漏洞

    • 在java等面向对象的编程语言中,异常本身就是一个类,产生异常就是创建异常对象并抛出一个异常对象

    • java异常处理的五个关键字

      • try、catch、finally、throws、throw

3.异常的分类

  • java.lang.Throwable:是所有异常和错误的超类

    • Exception:所有异常的基类

      • 编译时异常:ClassNotFoundException、IOException、SQLException,写代码时必须处理

      • 运行时异常:RuntimeException,

      • 如数组下标越界异常ArrayIndexOutOfBoundsException,

      • 空指针异常 NullPointerException

      • 程序运行过程中出现的异常

    • Error:编译时错误或系统错误

      • 出现错误,必须修改源代码,程序才能继续执行

4.常见的异常

  • Exception:所有异常的基类

  • ArithmeticException:计算异常

  • ArrayIndexOutOfBoundsException:数组下标越界异常

  • NullPointerException:空指针异常

  • ClassCastException:类转换异常

  • InputMismatchException:输入不匹配异常

  • ClassNotFoundException:无法加载某个类

  • NumberFormatException:数字格式转换异常

5.try-catch-finally,处理异常的第一种方式

public static void main(String[] args) {
    Scanner input = new Scanner(System.in);
    //try包含可能发生异常的代码
    try {
        System.out.println("请输入被除数:");
        int num1 = input.nextInt();
        System.out.println("请输入除数:");
        int num2 = input.nextInt();
        System.out.println(String.format("%d / %d = %d", num1, num2, num1 / num2));
    } catch (InputMismatchException ex) {
        //一旦出现输入不匹配异常,程序不会中断,会进入该catch中
        //给用户看
        System.out.println("请输入合理的数字");
        //打印报错信息
        ex.printStackTrace();
    } catch (ArithmeticException ex) {
        System.out.println("除数不可以为0");
        //输出详细异常信息
        System.out.println(ex.getMessage());
        //退出虚拟机
        System.exit(1);//0正常退出,1异常退出
    } catch (Exception e) {
        //是所有异常的基类,任何异常都能捕获到
        //三个catch的顺序不能变,子类在前,父类在后(小异常在前,大异常在后)
        System.out.println("输入有误,请重新的输入");
    } finally {
        //最后的,放在最后,始终执行
        //只有一种情况不会执行,就是还未执行到finally,就强制退出虚拟机了
        System.out.println("欢迎使用本程序");
    }
    System.out.println("最后的内容");
}

  • try:用来包含可能发生异常的代码

  • catch:用来捕获可能出现的异常信息,小异常(子类)在前,大异常(父类)在后

  • finally:用来收尾的,放在最后,无论发生异常与否,代码都会执行,只有一种情况不会执行,就是还未执行到finally,就强制退出了虚拟机。

  • 使用try-catch-finally,会有三种情况发生

    • 程序没有发生异常,不会进入到任何一个catch中,会执行finally中的代码及之后的代码

    • 程序发生异常并且捕获到了,会进入到对应的catch中进行相应处理,然后再执行finally中的代码及之后的代码

    • 程序发生异常,但是没有捕获到,只会执行finally中的代码

  • catch中的异常处理信息

    • 加入自定义的提示语言

    • 打印具体的报错信息

      • void printStackTrace(): 输出异常的堆栈信息(常用)

      • String getMessage(): 返回异常信息的描述字符串,是printStackTrace()输出信息的一部分

  • catch可以有多个

    • 一段代码可能发生多种异常,可以使用不同的catch块分别捕获

    • 依次从上往下进行匹配,一旦匹配上一个之后,其他的不再判断

    • catch顺序:先特殊,再普通,先子类,再父类

  • finally

    • 退出java虚拟机时不执行

      • System.exit(0):正常退出

      • System.exit(1):非正常退出

6.throws,处理异常的第二种方式

public static int divide()
        throws InputMismatchException, ArithmeticException, Exception {
    Scanner input = new Scanner(System.in);
    System.out.println("请输入被除数:");
    int num1 = input.nextInt();
    System.out.println("请输入除数:");
    int num2 = input.nextInt();
    return num1 / num2;
}
//调用抛出异常的方法需要对其声明的异常进行处理
//处理方式有两种
//第一种:try-catch,catch块中捕获的异常必须能够匹配使用throws关键字抛出的异常
public static void main(String[] args) {
    try {
        int num = divide();
    } catch (Exception e) {
        e.printStackTrace();
    }
​
}
​
//第二种方式:在方法的声明处继续声明抛出异常,代码出现异常后,程序直接中断
public static void main(String[] args) throws Exception {
    int num = divide();
    System.out.println("商是" + num);
}
  • 注意:

    • throws关键字只能必须写在方法声明处

    • throws关键字后面声明的异常必须是Exception或者是Exception的子类

    • 如果方法的内部抛出了多个异常,那么throws后面也必须声明多个异常

      • 如果抛出的多个异常有父子类关系,那么直接声明父类异常即可

    • 如果调用了一个抛出异常的方法,我们就必须处理声明的异常

      • 要么继续使用throws将异常抛出,交给方法的调用者处理,最终交给jvm

      • 要么使用try-catch自己处理异常

7.throw,自定义异常进行抛出

public class Student {
    private String name;//姓名
    private String sex;//性别
    
    public Student() {
​
    }
​
    public void setSex(String sex) throws Exception {
        if ("男".equals(sex) || "女".equals(sex)) {
            this.sex = sex;
        } else {
            throw new InputMismatchException("性别只能是“男”或“女”");
        }
    }
}
  • throw用在代码中,自定义要抛出的异常。throw new Exception("异常信息")

  • 如果自定义的是编译时异常,需要在方法的声明处添加throws声明异常

  • 调用方法时,使用try-catch捕获异常

  • public static void main(String[] args) {
        Student student = new Student();
        try {
            student.setSex("dd");
        } catch (Exception e) {
            e.printStackTrace();
        }
    ​
    }
    • catch的异常类型要和方法声明的异常类型相匹配(相同或包含)

  • 注意:

    • throw关键字必须写在方法的内部

    • throw关键字后面new的对象必须是Exception或者Exception的子类

    • throw关键字抛出指定的异常对象,就必须处理声明的异常

      • 如果创建的是运行时异常,可以不处理,交给jvm

      • 如果创建的是编译时异常,我们必须处理这个异常,要么try-catch,要么throws

8、日志工具log4j

  • 系统真正部署到用户处之后,无法使用控制台查看报错信息,我们需要将用户的关键操作以及报错信息记录到日志文件中

  • log4j是第三方提供的专门记录日志的一个工具

    • 我们在使用时需要将其引入,也就是将jar包加载到我们的项目中

  • 使用步骤

    • 引入jar包:在项目目录下创建lib文件夹,将jar包复制到lib目录下,右键lib目录,选择add as Library

    • 在src下创建配置文件:log4j.properties

      • 在文件中指定相关信息

      • ### 设置Logger输出级别和输出目的地 ###
        # 输出级别从高到低是:error、warn、info、debug
        log4j.rootLogger=debug,stdout,logfile
        ​
        ### 把日志信息输出到控制台 ###
        log4j.appender.stdout=org.apache.log4j.ConsoleAppender
        log4j.appender.stdout.Target=System.err
        log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
        ​
        ### 把日志信息输出到文件:test.log ###
        log4j.appender.logfile=org.apache.log4j.FileAppender
        log4j.appender.logfile.File=test.log
        log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
        log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n
    • 使用log4j

      • 创建日志对象:

        • 引入的是:import org.apache.log4j.Logger;

        • private static Logger logger = Logger.getLogger(TestTry.class.getName());
      • 使用相关方法记录日志信息

        public class TestTry {
            //创建日志对象
            private static Logger logger = Logger.getLogger(TestTry.class.getName());
        ​
            public static void main(String[] args) {
                Scanner input = new Scanner(System.in);
                //try包含可能发生异常的代码
                try {
                    System.out.println("请输入被除数:");
                    int num1 = input.nextInt();
                    //记录用户操作
                    logger.info("输入了被除数:" + num1);
                    System.out.println("请输入除数:");
                    int num2 = input.nextInt();
                    logger.debug("输入了除数:" + num2);
                    System.out.println(String.format("%d / %d = %d", num1, num2, num1 / num2));
                    logger.debug("结果是:" + num1 / num2);
                } catch (InputMismatchException ex) {
                    //一旦出现输入不匹配异常,程序不会中断,会进入该catch中
                    //给用户看
                    System.out.println("请输入合理的数字");
                    //打印报错信息
                    ex.printStackTrace();
                    logger.error("用户输入的不是数字");
                } catch (ArithmeticException ex) {
                    System.out.println("除数不可以为0");
                    //输出详细异常信息
                    System.out.println(ex.getMessage());
                    logger.error("用户输入了0做除数");
                    System.exit(1);
                } catch (Exception e) {
                    //是所有异常的基类,任何异常都能捕获到
                    //三个catch的顺序不能变,子类在前,父类在后(小异常在前,大异常在后)
                    System.out.println("输入有误,请重新的输入");
                } finally {
                    //最后的,放在最后,始终执行
                    //只有一种情况不会执行,就是还未执行到finally,就强制退出虚拟机了
                    System.out.println("欢迎使用本程序");
                }
                System.out.println("最后的内容");
        ​
            }
        }

  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值