JAVA - 异常

1.1 引入异常

生活中的异常:

正常情况下,李白每日开车去上班,耗时大约30分钟

但是,异常情况总是在某一天发生!

会怎么办呢?会根据情况灵活做出选择!

程序中的异常

示例1:给出除数和被除数,求商

  • 如果除数为0,出异常
  • 如果除数或者被除数不是数字,出异常

示例2:将d:/a.txt复制到e:/a.txt

  • 如果d:/a.txt不存在
  • 如果e:/存在a.txt
  • 如果e盘空间不足
  • 如果复制过程中出错

面对异常该怎么办呢?

方式1:由开发者通过if-else来解决异常问题

  • 代码臃肿:业务代码和异常处理代码放一起
  • 程序员要花很大精力"堵漏洞“
  • 程序员很难堵住所有“漏洞”,对程序员本身要求较高

方式2:开发者不需要通过if-else来解决异常问题,而是Java提供异常处理机制。它将异常处理代码和和业务代码分离,使程序更优雅,更好的容错性,高键壮性

异常( Exception  也称例外)就是在程序的运行过程中所发生的不正常的事件,它会中断正在运行的程序

  • 所需文件找不到
  • 网络连接不通或中断
  • 算术运算错 (被零除…)
  • 数组下标越界
  • 装载一个不存在的类或者对null对象操作
  •  类型转换异常
  • ……

当Java程序出现以上的异常时,就会在所处的方法中产生一个异常对象。这个异常对象包括异常的类型,异常出现时程序的运行状态以及对该异常的详细描述。

Java的异常处理是通过5个关键字来实现的:try、catch、 finally、throw、throws

 

1.try{} catch(){}

Java语言的异常捕获结构由try、catch和finally 3部分组成。其中,try语句块存放的是可能发生异常的Java语句;catch程序块在try语句块之后,用来激发被捕获的异常;finly语句块是异常处理结构的最后执行部分,无论ty语句块中的代码如何退出,都将执行 finally 语句块。

 语法如下∶

try{

/程序代码块}

catch(Exceptiontype1 e) {

/对 Exceptiontype1的处理 }

catch{Exceptiontype2 e){

//对 Exceptiontypo2的处理}

finally {/i程序块}

示例1:

public class TestException1 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        //输入总分
        System.out.println("请输入总分");
        int sum = input.nextInt();
        //输入人数
        System.out.println("请输入人数");
        int count = input.nextInt();
        //求平均分并输出
        int result = sum / count;
        System.out.println("result="+result);
        System.out.println("3q3q");
System.out.println("bye");
    }
}

情况1:总分和人数都正确输入,输出结果,并3q3q。

 情况2:人数为零,后面结果和3q3q不再输出

情况3:输入非数字,后面结果和3q3q不再输出

try{} 中放入可能发生异常的代码。catch{}中放入对捕获到异常之后的处理。其中catch中e.printStackTrace()作用就是,在控制台打印程序出错的位置及原因。try{} 中放入可能发生异常的代码。catch{}中放入对捕获到异常之后的处理。其中catch中e.printStackTrace()作用就是,在控制台打印程序出错的位置及原因。

只有try块中代码发生异常才会走到 catch块。

优点:Java已经提供了异常处理机制,发生异常后,会给出异常类型、异常提示信息、异常的位置

缺点:出现异常后,后续语句不执行了;提示信息太专业,可读性差

1.2 异常处理:try-catch-finally

示例2

public class TestException2 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try{
            //输入总分
            System.out.println("请输入总分");
            int sum = input.nextInt(); 
            //输入人数
            System.out.println("请输入人数");
            int count = input.nextInt();
            //求平均分并输出
            int result = sum / count;
            System.out.println("result="+result);
            return; // 方法结束,后面的语句不会执行
        }catch(Exception e){
            //输出异常的底层信息
            //e.printStackTrace();          
//System.out.println(e.toString());
//System.out.println(e.getMessage());/// by zero
        //输出用户自定义异常信息
        System.err.println("请检查人数是否为0,请检查是否输入了非数字内容");
        //继续向上抛出异常 (catch后面的语句就不执行了)
        //throw  e;
    }
        System.out.println("3q3q");
System.out.println("bye");
}
}

try-catch执行情况

  • 情况1:try块中代码没有出现异常

不执行catch块代码,执行catch块后边的代码

  • 情况2:try块中代码出现异常,catch中异常类型匹配(相同或者父类)

执行catch块代码,执行catch块后边的代码

  • 情况3:try块中代码出现异常, catch中异常类型不匹配

不执行catch块代码,不执行catch块后边的代码,程序会中断运行

注意:

  • 出现异常后,Java会生成相应的异常对象,Java系统,寻找匹配的catch块,找到后将异常对象付给catch块异常参数。
  • 出现异常后,try块中尚未执行的语句不会执行;
  • 出现异常后并处理后,catch块后面的语句还会执行

catch块中如何处理异常

  • 输出用户自定义异常信息

System.err.println("除数不能为零。");

System.err.println("被除数和除数必须是整数。");

  • 调用异常对象的方法输出异常信息

toString ( )方法,显示异常的类名和产生异常的原因

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

String getMessage()返回异常信息描述字符串,printStackTrace()信息一部分

  • 继续向上抛出异常throw e 

异常类型

说    明

Exception 

异常层次结构的根类

ArithmeticException

算术错误情形,如以零作除数

ArrayIndexOutOfBoundsException

数组下标越界

NullPointerException

尝试访问 null 对象成员

ClassNotFoundException

不能加载所需的类

InputMismatchException

欲得到数据类型与实际输入类型不匹配

IllegalArgumentException

方法接收到非法参数

ClassCastException

对象强制类型转换出错

NumberFormatException

数字格式转换异常,如把"ab"转换成数字

问题1:在什么情况下,catch后面的语句是不执行的

     情况1:throw e;

       情况2:发生的异常和catch中异常类型不匹配

       情况3:return

  问题2:不管什么情况下,希望某些语句都执行,怎么办

      finally语句

实例3

public class TestException3 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try{
            //输入总分
            System.out.println("请输入总分");
            int sum = input.nextInt(); 
            //输入人数
            System.out.println("请输入人数");
            int count = input.nextInt();
            //求平均分并输出
            int result = sum / count;
            System.out.println("result="+result);
            System.exit(0);//结束虚拟机的运行
            //return; // 方法结束,后面的语句不会执行
        }catch(Exception e){
            //输出用户自定义异常信息
            System.err.println("请检查人数是否为0,请检查是否输入了非数字内容");
            //继续向上抛出异常 (catch后面的语句就不执行了)
            throw  e;
        }finally{
            System.out.println("3q3q");
        }
        System.out.println("bye");
    }
}

问题3:return和finally语句的执行顺序

   执行return之前的语句----执行finally语句-----执行return

问题4:finally在实际开发中的使用场合

   IO流的管理,数据库连接的关闭   socket的关闭

问题5:唯一的例外

   System.exit(0); 终止当前正在运行的 Java 虚拟机。

 

问题:一段代码可能会引发多种类型的异常,是否可以分开处理

【示例4使用多重catch处理异常

public class TestException4 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try{
            //输入总分
            System.out.println("请输入总分");
            int sum = input.nextInt(); 
            //输入人数
            System.out.println("请输入人数");
            int count = input.nextInt();
            //求平均分并输出
            int result = sum / count;
            System.out.println("result="+result);
        }catch(InputMismatchException  e){ 
            System.err.println("请检查是否输入了非数字内容");
        }catch(ArithmeticException e){
            System.err.println("请检查人数是否为0");
        }catch(Exception e){
            //输出异常的底层信息
            System.err.println("other exception:"+e.toString());
        }
        finally{
            System.out.println("3q3q");
        }
        System.out.println("bye");
    }
}
  • 当引发异常时,会按顺序来查看每个 catch 语句,并执行第一个与异常类型匹配的catch语句
  • 执行其中一条 catch 语句后,其后 catch 语句将被忽略
  • 在安排catch语句的顺序时,首先应该捕获最特殊的异常,  然后再逐渐一般化,即先子类后父类  
  • JDK7异常新处理方式:catch(InputMismatchException | ArithmeticException e){}

 

2.异常体系

Error

Error类层次描述了Java运行时系统内部错误和资源耗尽错误,一般指与JVM或动态加载等相关的问题,如虚拟机错误,动态链接失败,系统崩溃等。

这类错误是我们无法控制的,同时也是非常罕见的错误。所以在编程中,不去处理这类错误。注:我们不需要管理Error!

 

Exception

所有异常类的父类,其子类对应了各种各样可能出现的异常事件。

 

Exception分类

  • 运行时异常Runtime Exception(unchecked Exception)

可不必对其处理,系统自动检测处理

一类特殊的异常,如被 0 除、数组下标超范围等,其产生比较频繁,处理麻烦,如果显式的声明或捕获将会对程序可读性和运行效率影响很大

  • 检查异常 Checked  Exception  

必须捕获进行处理,否则会出现编译错误。

注意:只有Java提供了Checked异常,体现了Java的严谨性,提高了Java的健壮性。同时也是一个备受争议的问题。

 

3 异常处理:throws、throw

3.1手动抛出异常throw

  • Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要手工创建并抛出。
  • 在捕获一个异常前,必须有一段代码先生成异常对象并把它抛出。这个过程我们可以手工做,也可以由JRE来实现,但是他们调用的都是throw子句。
  • 注意抛出运行时异常和Checked异常的区别
    1. 抛出Checked异常,该throw语句要么处于try块中,要么方法签名中石油throws抛出
    2. 抛出运行时异常,没有以上要求

 

 

3.2 声明异常throws

  • 当Checked Exception产生时,不一定立刻处理它,可以再把异常Throws出去
  • 如果一个方法抛出多个已检查异常,就必须在方法的首部列出所有的异常,之间以逗号隔开
  • 子类声明的异常范围不能超过父类声明范围:父类没有声明异常,子类也不能;不可抛出原有方法抛出异常类的父类或上层类

示例5:throw和throws的使用1:除数不能是负数

public class TestException6 {
    public static void main(String[] args) throws Exception {
        try {
            getAvg();
        } catch (Exception e) {
            e.printStackTrace();
        }
        getAvg();
    }
    public static void getAvg() throws Exception {
        try{
            Scanner input = new Scanner(System.in);
            //输入总分
            System.out.println("请输入总分");
            int sum = input.nextInt();

            //输入人数
            System.out.println("请输入人数");
            int count = input.nextInt();
            if(count<0){
               //throw  new RuntimeException("人数不能是负数:"+count);
               throw  new Exception("人数不能是负数:"+count);
            }
            //求平均分并输出
            int result = sum / count;

            System.out.println("result="+result);
        }catch (ArithmeticException e){
            e.printStackTrace();
        }catch (InputMismatchException e){
            e.printStackTrace();
        }catch (Exception e){
            //先处理
            e.printStackTrace();
            //再抛出
            throw e;
        }finally{
            System.out.println("3q3q");
        }

        System.out.println("bye");
    }

 

3.3 自定义异常

在程序中,可能会遇到任何标准异常类都没有充分的描述清楚的问题,这种情况下可以创建自己的异常类。

从Exception类或者它的子类派生一个子类即可。习惯上,定义的类应该包含2个构造器:一个是默认构造器,另一个是带有详细信息的构造器

示例:字定义异常

public class AgeException extends RuntimeException {
    public AgeException() {
    }
    public AgeException(String message) {
        super(message);
    }
}
public class CountMinusException extends Exception {
    public CountMinusException() {
        super();
    }
    public CountMinusException(String message) {
        super(message);
    }
}
//throw new CountMinusException("人数不能是负数:"+count);
//throw new AgeException("年龄错误,必须在1-120岁之间:"+age);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值