zoukankan      html  css  js  c++  java
  • 11_异常处理

    传统的异常处理
    public class Test01 {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入被除数:");
            int num1, num2;
            if (sc.hasNextInt()) {
                num1 = sc.nextInt();
                System.out.println("请输入除数:");
                if (sc.hasNextInt()) {
                    num2 = sc.nextInt();
                    if (0 == num2) {
                        System.out.println("除数不能为0");
                    } else {
                        int r = num1 / num2;
                        System.out.println("r=" + r);
                    }
                } else {
                    System.out.println("除数输入有误!");
                }
            } else {
                System.out.println("被除数输入有误!");
            }
        }
    }
    传统异常处理是通过if条件判断来处理的:
    [1] 效率极低
    [2] 业务逻辑和异常处理交织在一起,维护性差。
    异常处理机制
    异常的概念
    异常是指在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序
    通过异常处理机制,我们不能过度使用异常。
     
    异常处理
    try-catch
    把可能产生异常的代码放入try代码块中。如果没有产生异常,程序不会执行catch代码块。如果产生异常,执行catch代码块,程序继续执行。
    public class Test01 {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入被除数:");
            int num1, num2;
            try {
                num1 = sc.nextInt();
                System.out.println("请输入除数:");
                num2 = sc.nextInt();
                
                int r = num1 / num2;
                System.out.println("r = " + r);
                
            } catch (Exception e) {
                System.out.println("oops,产生异常:"+e);
            }
            
            System.out.println("程序结束...");
        
        }
    }
    Exception 类是所有异常类的父类。
    如果程序在try中产生异常,进入catch前需要类型匹配,所以写多个catch代码块。
    try {
                num1 = sc.nextInt();
                System.out.println("请输入除数:");
                num2 = sc.nextInt();
                
                int r = num1 / num2;
                System.out.println("r = " + r);
                
            } catch (InputMismatchException e) {
                System.out.println("产生输入不匹配异常:"+e);
            } catch (ArithmeticException e) {
                System.out.println("产生数学计算异常:"+e);            
            } catch(Exception e) {
                System.out.println("通用异常:"+e);
            }
    通常需要一个Exception用于匹配所有异常,一般放到最后一个catch块中。如果前方有匹配异常,Exception不在匹配。
     
    Excepiotn 常用方法
    [1] toString() 输出异常的类型和描述信息
    e.g: java.lang.ArithmeticException: / by zero
     
    [2] getMessage() 返回异常的描述信息
     
    [3] printStackTrace() 打印执行堆栈
    java.util.InputMismatchException
    at java.util.Scanner.throwFor(Scanner.java:864)
    at java.util.Scanner.next(Scanner.java:1485)
    at java.util.Scanner.nextInt(Scanner.java:2117)
    at java.util.Scanner.nextInt(Scanner.java:2076)
    at cn.exception02.Test02.main(Test02.java:14)
    第一行:toString()的返回值
    最后一行:出现异常的方法和出现异常的具体行数
     
    注意:e.printStackTrace() 在控制中输出的位置不是按照程序流程输出的。
    System.err.println() 在控制台中以红色字体提示错误信息。
     
    try-catch-finally
    [1]try-catch和之前一样用法,finally代码块表示不管是否出现异常,都执行的代码块。
    public class Test01 {
        public static void main(String[] args) {
            
            Scanner sc = new Scanner(System.in);
            
            try {
                sc.nextInt();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("finally 代码块");
            }
            System.out.println("程序结束");
        }
    }
    finally 代码块中一般用于放置一些关闭数据库、关闭文件、关闭网络连接等释放资源的代码。
    try {
       // 打开数据库
       // 增删改查
    } catch (Exception e) {
       // 异常处理
    } finally {
    // 关闭数据库
    }
    [2] 存在return try-catch-finally代码块的执行顺序
    public static int add() {
            System.out.println("请输入第一个操作数:");
            Scanner sc = new Scanner(System.in);
            int num1, num2;
            int r = 0;
            try {
                num1 = sc.nextInt();
                System.out.println("请输入第二个操作数:");
                num2 = sc.nextInt();
                r = num1 + num2;
                
                return r;
            } catch (Exception e) {
                System.out.println("出现异常.");
                return r;
            } finally {
                System.out.println("finally");
                sc.close();
            }
        }
    [3]jvm 退出时finally代码块不在执行。
    public class Test02 {
        public static void main(String[] args) {
            
            Scanner sc = new Scanner(System.in);
            
            try {
                sc.nextInt();
                System.exit(0);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("finally 代码块");
            }
            
            System.out.println("程序结束");
        }
    }
    多重catch块
    多重catch可以用到try-catch中,也可以用到try-catch-finally中。
    原则:
    [1] 先子类后父类
    [2] 发生异常时按顺序逐个匹配
    [3] 只执行第一个与异常类型匹配的catch语句
     
    异常的分类
    Throwable 类是 Java 语言中所有错误(Error)或异常(Exception)的父类,只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
     
    Error 类表示错误类。仅靠程序本身无法恢复的严重错误。jvm内存耗尽、jvm崩溃等。
    Exception 类表示异常类,可以通过java 异常处理机制处理。
     
    Exception 更加是否处理分为两种情况。
    RuntimeException:运行时异常。不要求程序必须做出处理。是所有运行时异常的父类。
    CheckedException:检查时异常。要求程序必须处理,不处理编译不通过。
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Scanner;
    public class Test01 {
        public static void main(String[] args) {
            
            // 运行时异常
            /*Scanner sc = new Scanner(System.in);
            System.out.println("请输入1-3之间的数字:");
            int num = sc.nextInt();
            System.out.println(num);*/
            
            
            // 检查时异常
            try {
                SimpleDateFormat df = new SimpleDateFormat();
                df.parse("123");
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }
    常见的运行时异常
    ArithmeticException:数学计算异常。比如除数为0
    ArrayIndexOutofBoundsException:数组下标越界异常。
    NullPointException:空指针异常
    IllegalArgumentException:非法参数异常。
    ClassCastException:强制类型转换异常。
    NumberFormatException:数字格式化异常。比如把“abc”格式化成数字。
     
    常见的检查时异常:
    ClassNotFoundException:类没有被发现异常。
    SQLException:数据库先关异常
    IOException:IO操作异常
    ParseException:解析错误异常
    FileNotFoundException:文件未发现异常。
     
    运行时异常和检查时异常的区别
    运行时异常:包括RuntimeaException及其所有子类。不要求程序必须对它们作出处理,比如InputMismatchException、ArithmeticException、NullPointerException等。即使没有使用try-catch或throws进行处理,仍旧可以进行编译和运行。如果运行时发生异常,会输出异常的堆栈信息并中止程序执行。
    Checked异常(非运行时异常):除了运行时异常外的其他异常类都是Checked异常。程序必须捕获或者声明抛出这种异常,否则出现编译错误,无法通过编译。处理方式包括两种:通过try-catch捕获异常,通过throws声明抛出异常从而交给上一级调用方法处理
     
     
     
     
     
    声明异常
    声明异常的概念
    当一个方法可能存在异常时,如果不想在方法内处理(不合适在方法内处理、想让调用者处理)时,可以选择在方法上声明异常。形式:
    public 返回值 方法名(形参) throws 异常类1,异常类2,…{
    }
    public static int div(int a,int b) throws ArithmeticException{
            int r = a / b;
            return r;
        }
    所谓声明异常,就是当调用者调用该方式时知道该方法可能产生异常,并处理异常。
    public class Test01 {
        
        public static int div(int a) throws ArithmeticException,InputMismatchException{
            System.out.println("请输入第二个参数:");
            Scanner sc = new Scanner(System.in);
            int b = sc.nextInt();
            int r = a / b;
            return r;
        } 
        
        public static void main(String[] args) {
            
            // 处理div声明的异常
            try {
                Test01.div(10);
            } catch (InputMismatchException | ArithmeticException e) {
                e.printStackTrace();
            }
        }
    }
    如果一个方法抛出异常必须被外界(调用处)处理时,可以声明检查时异常。否则,声明运行时异常。
    public class Test02 {
        
        //    声明检查时异常
        public static int div(int a) throws Exception{
            System.out.println("请输入第二个参数:");
            Scanner sc = new Scanner(System.in);
            int b = sc.nextInt();
            int r = a / b;
            return r;
        } 
        
        public static void main(String[] args) {
            try {
                Test02.div(10);
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
    }
    如果在方法调用处也不知道如何处理时,可以选择继续向上抛出异常。
    直到在main方法上声明异常。此时如果main方法执行时产生异常,jvm负责处理。
    import java.util.InputMismatchException;
    import java.util.Scanner;
    public class Test03 {
        
        //    声明检查时异常
        public static int div(int a) throws Exception{
            System.out.println("请输入第二个参数:");
            Scanner sc = new Scanner(System.in);
            int b = sc.nextInt();
            int r = a / b;
            return r;
        } 
        
        
        public static void main(String[] args) throws Exception{
        
            // 调用处也不知道如何处理,继续上抛异常 => 在main上声明异常。
            Test03.div(10);
            
        }
    }
    总结:
    声明异常实际上就是一个异常上抛的过程。
     
    重载的关系
    声明异常和重载没有任何关系
     
    重写的关系
    声明一个和重写有关系
     
    [1] 如果父类声明了运行时异常,子类可以不声明任何异常或者继承声明运行时异常。
    package cn.exception07;
    public class Father {
        
        public void showInfo() throws RuntimeException{
            System.out.println("father:showInfo");
        }
    }
    package cn.exception07;
    public class Son extends Father{
        @Override
        public void showInfo() {
            super.showInfo();
            System.out.println("我是son:showInfo");
        }
    }
    [2] 如果父类没有声明异常,子类不用声明异常或者可以声明运行时异常。
    public class Father {
        
        public void showInfo() {
            System.out.println("father:showInfo");
        }
    }
    @Override
        public void showInfo() throws RuntimeException{
            super.showInfo();
            System.out.println("我是son:showInfo");
        }
    [3] 如果父类声明了Exception,子类要么在内部处理掉,要么继续向上抛。
    public class Father {
        
        public void showInfo() throws Exception{
            System.out.println("father:showInfo");
        }
    }
    public class Son extends Father{
        @Override
        public void showInfo() {
            
            try {
                super.showInfo();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("我是son:showInfo");
        }
    }
    public class Son extends Father{
        @Override
        public void showInfo() throws Exception {
            
            super.showInfo();
            System.out.println("我是son:showInfo");
        }
    }
    手动抛出异常
    除了jdk自身抛出的异常,开发者可以根据业务需要手动抛出异常。使用关键字throw
    public void setAge(int age) throws Exception{
            if(age > 0) {            
                this.age = age;
            }else {
                throw new Exception("年龄不合法");
            }
        }
    如果要抛出必须处理的异常,throw new Exception;
    如果要抛出可以处理可不处理的异常,throw new RuntimeException
     
    自定义异常
    很多时候,jdk中定义的异常根本不能满足具有业务的需要。可以考虑自定义异常。
    步骤:
    [1] 继承异常类(Exception/RuntimeException)
    [2] 定义构造方法。一般需要调用父类的构造方法。
    public class AgeException extends Exception{
        public AgeException() {
            super();
        }
        public AgeException(String message) {
            super(message);
        }
        
        public int showInfo() {
            System.out.println(this.getClass()+"=>"+super.getMessage());
            return 0;
        }
    } 
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    TCP三次握手四次挥手
    TCP与UDP的区别
    mysql从库设置全局只读,并创建普通账号
    docker安装mysql主从
    mysql 更换数据目录
    Docker 部署 ElasticSearch
    js获取地址栏传参
    PHP-MySQL基本操作
    基于element-tree-table树型表格点击节点请求数据展开树型表格
    拖拽读取文件
  • 原文地址:https://www.cnblogs.com/aknife/p/10890097.html
Copyright © 2011-2022 走看看