Java的异常处理

一 .异常的基本概念和作用
  所谓异常就是Java在运行过程中出现的错误。如用户输入了错误的数据文件无法打开等操作。由于异常事件的发生会导致严重的错误,一个好的程序应该考虑到这些错误情况,并有相应的处理手段,这就是程序的“健壮性”。
使用异常处理机制的三个优势。

  • 在使用传统语言编程,我们只能通过函数的返回值知道错误信息,因此需要些很多的 if-else 之类的判断语句,而且这些判断语句通常是嵌套的,导致程序可读性降低,代码也难于维护。
      采用异常处理机制后,写程序时可以认为不会发生异常,一直按照正常的程序处理流程写下去,知道最后在捕获异常并进行相应的处理手段就可以了
  • 由于函数只有一个返回值,所以难以区分到底是正常值还是错误信息的代码。
       采用异常处理机制后则不会发生这种情况。一旦有错误发生,被调用的方法会抛出异常。不用去判断到底是那一步错了。
  • 在传统语言中,错误代码需要调用链上的函数一层一层返回。例如有这样的调用链:A->B->C->D,如果D发生错误,将返回一个错误代码,如果C和B不处理这个错误,就必须将这个错误返回给上一级,。如果函数编写者忘了编写这一项,函数A就不会得到错误信息。
      采用异常处理机制后,在D中抛出的异常就会存放在异常栈中,如果C和B不处理,仍然会传递给A,极端情况下即使A不处理它,系统也会处理它。

二 .异常的继承体系图如下
在这里插入图片描述
Java中有两种不同的异常处理方式:

  • 一种是自己利用Java异常处理机制将该问题处理,然后继续执行。
  • 另一种是自己没有针对的处理方式,交给调用main的jvm来处理(jvm有一个默认的异常处理机制,将该异常处理,并将该异常的名称,信息,以及异常出现的位置打印在控制台上同时将程序停止执行)。
    异常

三 .异常处理方式

  • try…catch…finally
  • throws

try…catch处理异常的基本格式

 try	{
            可能出现问题的代码 ;
        }catch(异常名1 变量名){
            针对问题的处理 ;
        }catch(异常名2 变量名){
            针对问题的处理 ;
        }
        finally{
            释放资源;
        }

变形格式

  try	{
            可能出现问题的代码 ;
        }catch(异常名 变量名){
            针对问题的处理 ;
        }

在这里需要注意的时try…catch的方式可以处理多个异常,在捕获异常的时候能明确的异常尽量就明确,另外在捕获异常时平级关系的异常那个在前无所谓,但是如果出现了继承关系,那么父类必须在后面。

public class MyTest1 {
    public static void main(String[] args) {
       int a = 10;
       int b = 0;
       int[]c = {1,2};
       c = null;
       try{
           System.out.println(c[3]);
           System.out.println(a / b);
       }catch (ArithmeticException e){

           System.out.println("除数为0了");
           e.printStackTrace();//打印异常的堆栈信息
        }catch (NullPointerException e){
           System.out.println("空指针异常");
           e.printStackTrace();
       }catch (Exception e){
           System.out.println("其他异常");
       }
       finally {
           System.out.println("程序结束");
       }
        System.out.println("代码执行");
    }
}

运行结果为:

空指针异常
java.lang.NullPointerException
程序结束
	at org.westos.demo4.MyTest1.main(MyTest1.java:10)
代码执行

  在上面的代码中经过实验,如果把除数为0与空指针异常调换位置,那么输出的就是除数为0异常,空指针异常就不会输出。因此当有多个异常时catch语句中只能捕获一种,另外可以发现finally中的代码时肯定会执行的,并且finally之后的代码也是会执行的。

JDK1.7之后推出了多个异常的处理方案

  try {
           可能出现问题的代码 ;
           }catch(异常名1 | 异常名2 | ....   变量名){
           对异常的处理方案 ;
           }

优点:简化了代码。
缺点:对多个异常的处理方式是一致的,不能明确到底是哪一个出现了异常。

四 . Java中的异常通常分为两类:

  • 编译期异常(非RuntimeException类及其子类的实例)
      Java程序必须显示处理,否则程序就会发生错误,无法通过编译
  • 运行期异常(RuntimeException类及其子类的实例)
      无需显示处理程序依旧可以执行

throws的方式处理异常
  定义功能方法时,需要把出现的问题暴露出来让调用者去处理。那么就通过throws在方法上标识。
throw的方式处理异常
  在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。

五 .编译期异常发生在编译期。必须处理通常有两种处理方式

  • thorws把编译器异常跑出去给调用者,谁调用谁处理
  • 捕获处理

编译器的注意事项

  • 子类重写父类方法时,子类的方法必须抛出相同的异常,或者父类异常的子类,或者子类不抛出异常。
  • 如果父类抛出了多个异常,子类重写父类方法是,只能抛出相同的异常或者其子类,子类不能抛出父类没有的异常,或者子类不抛出异常
  • 如果被重写的方法没有抛出异常,那么子类的方法不可以抛出异常,如果子类产生异常,那么子类只能用try不能用throws抛出。

第一种抛出处理

import java.text.ParseException;
import java.text.SimpleDateFormat;

public class MyTest3 {
    public static void main(String[] args) {
        try {
            parse();
        }catch (ParseException e){
            e.printStackTrace();
        }finally {
            System.out.println("释放资源");
        }
        System.out.println(12345);

    }

    private static void parse() throws ParseException {
        String str = "2019-5-17";
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(dateFormat.parse(str));
    }
}

运行结果为:

Fri May 17 00:00:00 CST 2019
释放资源
12345

第二种捕获处理

import java.text.ParseException;
import java.text.SimpleDateFormat;

public class MyTest4 {
    public static void main(String[] args) {

        parseDate();
    }

    private static void parseDate()  {
        String str = "2019-4-27";
        SimpleDateFormat dateFormat =  new SimpleDateFormat("yyyy-MM-dd");
        try {
            System.out.println(dateFormat.parse(str));
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

运行结果为:

Sat Apr 27 00:00:00 CST 2019

六 .运行时处理异常的处理方式
捕获处理

public class MyTest5 {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        int[] arr = {1, 2};
        try {
            System.out.println(a / b);
            System.out.println(arr[7]);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } catch (NullPointerException e1) {
            e1.printStackTrace();
        } finally {
            System.out.println("释放资源");
        }
        System.out.println(123);
    }
}

运行结果为:

java.lang.ArithmeticException: / by zero
释放资源
	at org.westos.demo4.MyTest5.main(MyTest5.java:9)
123

七.自定义异常
  在实际的开发中jdk不可能对每一个异常都有与之对应的异常类,因此需要我们自己定义异常类,该类继承自Exception 或者是RuntimeException。
  例如判断成绩的范围是[0,100],此时就需要自己定义异常类。

public class NumException extends RuntimeException {
    public NumException() {
    }
    public NumException(String s){
        super(s);
    }
}

import java.util.Scanner;

public class MyTest6 {
    public static void main(String[] args) {
       Scanner sc =  new Scanner(System.in);
        System.out.println("请输入你的成绩0-100");
        int score = sc.nextInt();
        testScore(score);
    }

    private static void testScore(int score) {
       if(score>100||score<0){
           throw new NumException("成绩不合法");
       }else{
           System.out.println(score);
       }
    }
}

运行结果为:

请输入你的成绩0-100
99
99

八. throw和throws的区别

 throw

  • 用在方法体内,跟的是异常对象名
  • 只能抛出一个异常的对象名,这个异常对象可以是编译器异常也可以是运行时异常,表示抛出的异常,由方法体内的语句处理。
  • throw是抛出了异常,执行throw则一定是抛出了某种异常

 throws

  • 用在方法声明后,跟的是异常类名,可以跟多个异常类名,用逗号隔开
  • 表示抛出异常,由该方法的执行者进行处理
  • throws表示的是抛出异常的一种可能性,并不一定会发生这些异常。
import java.util.InputMismatchException;
import java.util.Scanner;

public class MyTest2 {
    public static void main(String[] args) {
        while (true){
            Scanner sc = new Scanner(System.in);
            try{
            System.out.println("请输入一个整数");
            int i = sc.nextInt();
            break;
            }catch (InputMismatchException e){
                System.out.println("你输入的格式不正确");
            }
        }
    }
}

运行结果:

请输入一个整数
r
你输入的格式不正确
请输入一个整数
2

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值