大数据——Java中异常的捕获和处理

异常的概述

认识异常

生活中的异常 :
正常情况下,小王每日开车去上班,耗时大约30分钟

在这里插入图片描述
但是,异常情况迟早要发生!
在这里插入图片描述
这就是一种很常见的生活中的异常。
异常是指在程序的运行的过程中所发生的不正常事件,如所需的文件找不到、网络连接不通或连接中断、算术运算出错(如被零除)、数组下标越界、装载一个不存在的类、对null对象操作、类型转换异常等、异常会中断正在运行的程序。
程序中的异常:
示例一:
编写程序实现根据提示输入被除数和除数,计算并输出商,最后输出“感谢使用本程序!”信息。

import java.util.Scanner;
public class Test1{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
System.out.print("请输入被除数:");
int num1 = in.nextInt();
System.out.print("请输入除数:");
int num2 = in.nextInt();
System.out.println(num1+"/"+ num2 +"="+ num1/ num2);
System.out.println("感谢使用本程序!");
}
}

正常情况下,用户会按照系统的提示输入整数,除数不能为0。输出结果:
在这里插入图片描述
但是,如果用户没有按要求进行输入,如被除数输入了B,则程序运行时将会发生异常,输出结果:
在这里插入图片描述
若除数输入了0,则程序运行时也将发生异常,输出结果:
在这里插入图片描述
从运行结果可以看出,一旦出现异常程序将会立刻结束,不仅计算和输出商的语句不会执行,就连输出“感谢使用本程序!”的语句也不会执行。可以通过增加if-else语句对各种异常情况进行判断处理。
示例二:
使用if-else语句处理示例一种的异常。

import java.util.Scanner;
public class num {
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        System.out.print("请输入被除数:");
        int num1 = 0;
        if(in.hasNextInt()){ //如果输入的被除数是整数
            num1=in.nextInt();
        }else {                //如果输入的被除数不是整数
            System.err.println("输入的被除数不是整数,程序退出。");
            System.exit(1);// 结束程序
        }
        System.out.print("请输入除数:");
        int num2=0;
        if(in.hasNextInt()){     //如果输入的除数是整数 
            num2=in.nextInt();
            if(0==num2){             //如果输入的除数是0
                System.out.println("输入的除数是0,程序退出。");
                System.exit(1);
        }
        }else{                     //如果输入的除数不是整数
            System.out.println("输入的除数不是整数,程序退出。");
            System.exit(1);
        }
        System.out.println(num1+"/"+ num2 +"="+ num1/ num2);
        System.out.println("感谢使用本程序!");
    }
}

通过if-else语句进行异常处理,有以下缺点:
代码臃肿,加入了大量的异常情况的判断和处理代码。
程序员把相当多的精力放在了异常处理代码上,放在了“堵漏洞”上,占用了编写业务代码的时间,必然影响开发效率。
很难穷举所有的异常情况,程序仍旧不健壮。
异常处理代码和业务代码交织在一起,影响代码的可读性,加大日后程序的维护难度。
生活中面对异常通常会这样处理:
在这里插入图片描述
生活中,根据不同的异常进行相应的处理,而不会就此中断我们的生活。
Java提供了异常处理机制,可以由系统来处理程序在运行过程中可能出现的异常事件,使程序员有更对的精力关注于业务代码的编写。

Java异常体系结构

Java中的异常有很多类型,异常在Java中被封装成了各种异常类。Java的异常体系结构如下所示:
在这里插入图片描述
所有异常类型都是Throwable类的子类,它派生了两个子类:Error类和Exception类。
(1)Error类:表示仅靠程序本身无法恢复的严重错误,如内存溢出、动态链接失败、虚拟机错误。应用程序不应该抛出这种类型的错误(一般由虚拟机抛出)。假如出现这种错误,应尽力使程序安全退出。所以在进行程序设计时,应该更关注Exception类。
(2)Exception类:由Java应用程序抛出和处理的非严重错误,如所需文件找不到、网络连接不通或连接中断、算术运算中断(如被除零)、数组下标越界、装载一个不存在的类、对null对象操作、类型转换异常等。它的各种不同的子类分别对应不同类型的异常。Exception又可分为来两大类异常:
运行时异常:包括RuntimeException及其所有子类。不要求程序必须对它们进行处理,如示例一中的ArithmeticException。
Checked异常(非运行是异常):除了运行时异常外的其他从Exception类继承来的异常类。
现阶段只需要初步了解这些异常类即可。在以后的编程中,可以根据系统报告的异常信息,分析异常类型来判断程序到底出现了什么问题。
常见的异常类型:

异常说明
Exception异常层次结构的根类
ArithmeticException算术错误异常,如以零作为除数
ArrayIndexOutOfBoundsException数组下标越界异常
NullPointerException尝试访问null对象成员
ClassNotFoundException不能加载所需的类
InputMismatchException欲得到的数据类型与实际输入的类型不匹配
IllegalArgumentException方法接收到非法参数
ClassCastException对象强制类型转换错误
NumberFormatException数字格式转换异常,如把“abc”转换成数字

Java异常处理机制

异常处理

Java编程语言使用异常处理机制为程序提供了错误处理的能力。
在这里插入图片描述
异常处理机制就像人们对平时可能遇到的意外情况,预先想好了一些处理的办法。在程序执行代码时,若发生了异常,程序会按照预定的处理办法对异常进行处理,异常处理完毕后,程序继续执行。
Java的异常处理通过5个关键字来实现的,即try、catch、finally、throw和throws。
在这里插入图片描述

使用try-catch处理异常

Java 中提供了try-catch结构进行异常捕获和处理,把可能出现异常的代码放入try语句块中,并使用catch语句块捕获异常。
示例三:
使用try-catch捕获并处理异常。

import java.util.Scanner;
public class num{
    public static void main(String[] args){
        try {
            Scanner in = new Scanner(System.in);
            System.out.print("请输入被除数:");
            int num1 = in.nextInt();
            System.out.print("请输入除数:");
            int num2 = in.nextInt();
            System.out.println(num1 + "/" + num2 + "=" + num1 / num2);
            System.out.println("感谢使用本程序!");
        }catch (Exception e){
            System.err.println("出现错误:被除数和除数必须是整数,“+”除数不能为零。");
            e.printStackTrace();
        }
    }
}

try-catch语句块的执行流程比较简单,首先执行的是try语句块中的语句,这时可能会出现以下3种情况。
(1)如果try语句块中所有语句正常执行完毕,没有发生异常,那么catch语句块中的所有语句都将会被忽略。当在控制台输入两个整数时,示例3中的try语句块中的代码将正常执行,不会执行catch语句块中的代码。
(2)如果try语句块在执行过程中发生异常,并且这个异常与catch语句块中声明的异常类型匹配,那么try语句块中剩下的代码都将被忽略,而相应的catch语句块将会被执行。匹配是指catch所处理的异常类型与所生成的异常类型完全一致或是它的父类。当在控制台提示输入入被除数时输入了“B",示例3中try语句块中的代码:“int num1=in.nextInt();"将抛出AismatchException异常。由于InputMismatchException是Exception的子类,程序将忽略try语句块中剩下的代码而去执行catch语句块。输出结果:
在这里插入图片描述
如果输入的除数为0,输出结果:
在这里插入图片描述
(3)如果try语句块在执行过程中发生异常,而抛出的异常在catch语句块中没有被声明,那么方法立刻退出。
如示例3所示,在catch语句块中可以加入用户自定义处理信息,也可以调用异常对象的方法输出异常信息,常用的方法如下。
➢void printStackTrace():输出异常的堆栈信息。堆栈信息包括程序运行到当前类的执行流程,它将输出从方法调用处到异常抛出处的方法调用序列。
String getMessage():返回异常信息描述字符串,该字符串描述了异常产生的原因,是printStackTrace()输出信息的一部分。
注意:如果try语句块在执行过程中发生异常,try语句块中剩下的代码都将被忽略,系统会自动生成相应的异常对象,包括异常的类型、异常出现时程序的运行状态及对该异常的详细描述。如果这个异常对象与cac语句块中声明的异常类型匹星-配,会把该异常对象赋给catchatch后面的异常参数,相应的catch语句块将会被执行。

使用try-catch-finally处理异常

如果希望示例了中不管是否发生异常,都执行输出“感谢使用本程序!"语句块,就需要在try-catch语句块后加入finally语句块,把要执行输出的语句放入finally语句块中。无论是否发生异常,finally语句块中的代码总能被执行。
示例四:使用try-catch-finally捕获并处理异常。

import java.util.Scanner;
public class num{
    public static void main(String[] args){
        try {
            Scanner in = new Scanner(System.in);
            System.out.print("请输入被除数:");
            int num1 = in.nextInt();
            System.out.print("请输入除数:");
            int num2 = in.nextInt();
            System.out.println(num1 + "/" + num2 + "=" + num1 / num2);
            System.out.println("感谢使用本程序!");
        }catch (Exception e){
            System.err.println("出现错误:被除数和除数必须是整数,除数不能为零。");
            e.printStackTrace();
        }
        finally {
            System.out.println("/by zero");
            System.out.println("感谢使用本程序!");
        }
    }
}

try-catch-finally 语句块的执行流程大致分为如下两种情况。
(1)如果try语句块中所有语句正常执行完事,fnally 语句块也会被执行。例如,当在控制台输入两个数字时,示例四中的try语句块中的代码将正常执行,不会执行catch语句块中的代码,但是fnally语句块中的代码将被执行。
(2)如果try语句块在执行过程中发生异常,无论这种异常能否被catch语句块捕获到,都将执行fnally语句块中的代码。例如,当在控制台输入的除数为0时,示例四中的try语句块中将抛出异常,进入catch语句块,最后fnally语句块中的代码也将被执行。输出结果:
在这里插入图片描述
try-catch-finally 结构中try语句块是必须存在的,catch、finally 语句块为可选,但两者至少出现其中之一。
需要特别注意的是,即使在catch 语句块中存在returm 语句,fnally 语句块中的语句也会执行。发生异常时的执行顺序是,先执行cach语句块中returmn 之前的语句,再执行finally语句块中的语句,最后执行catch语句块中的return语句退出。
finally语句块中语句不执行的唯一情况是在异常处理代码中执行了System.exit(1)退出Java虚拟机。如下所示:
示例五:在try-catch-finally结构的catch语句块中执行System.exit(1)退出Java虚拟机。

import java.util.Scanner;
public class num{
    public static void main(String[] args){
        try {
            Scanner in = new Scanner(System.in);
            System.out.print("请输入被除数:");
            int num1 = in.nextInt();
            System.out.print("请输入除数:");
            int num2 = in.nextInt();
            System.out.println(num1 + "/" + num2 + "=" + num1 / num2);
            System.out.println("感谢使用本程序!");
        }catch (Exception e){
            System.err.println("出现错误:被除数和除数必须是整数,除数不能为零。");
            System.exit(1);//finally语句块不执行的唯一情况
            //return;//finally语句块仍旧会执行
        }finally {

            System.out.println("感谢使用本程序!");
        }
    }
}

输出结果:在这里插入图片描述

使用多重catch处理异常

在计算并输出商的示例中,至少存在两种异常情况,输入非整数内容和除数为0,在示例四中统-按照Exception类型捕获,其实可使用多重catch语句块分别捕获并处理对应异常。
一段代码可能会引发多种类型的异常,这时,可以在一个try语句块后面跟多个catch语句块分别处理不同的异常。但排列顺序必须是从子类到父类,最后一个一般都是Exception类。因为按照匹配原则,如果把父类异常放到前面,后面的catch语句块将不会获得执行机会。
运行时,系统从上到下分别对每个catch语句块处理的异常类型进行检测,并执行第一个与异常类型匹配的catch语句。执行其中的一条catch语句之后,其后的catch语句将被忽略。
对示例四进行修改。
示例六:使用多重catch处理异常。

import java.util.InputMismatchException;
import java.util.Scanner;
public class num{
    public static void main(String[] args){
        try {
            Scanner in = new Scanner(System.in);
            System.out.print("请输入被除数:");
            int num1 = in.nextInt();
            System.out.print("请输入除数:");
            int num2 = in.nextInt();
            System.out.println(num1 + "/" + num2 + "=" + num1 / num2);
        }catch (InputMismatchException e){
            System.out.println("被除数和除数必须是整数。");
        }catch (ArithmeticException e){
            System.out.println("整数不能为零。");
        }catch (Exception e){
            System.out.println("其他未知异常。");
        }finally {
            System.out.println("感谢使用本程序!");
        }
    }
}

程序运行后,如果输入的不是整数,系统会抛出InputMismatchEXception异常对象,因此进入第一个catch语句块,并执行其中的代码,而其后的catch语句块将被忽略。输出结果:
在这里插入图片描述
如果系统提示输入被除数时输入“200”,系统会接着提示输入整数,当输入“0”是,系统会抛出ArithmeticException异常对象,因此进入第二个catch语句块并执行其中的代码,其他的catch语句块将被忽略。输出结果:
在这里插入图片描述
提示:在使用多重catch语句块时,catch语句块的排列顺序必须是子类到父类。最后一个一般都是Exception类。

使用throws声明抛出异常

如果在一个方法体中抛出了异常,并希望调用者能够及时地捕获异常,Java语言中通过关键字throws声明某个方法可能抛出的各种异常以通知调用者。throws可以同时声明多个异常,之间用逗号隔开。
在下面的实例七中,把计算并输出商的任务封装在了divide()方法中,并在方法的参数列表后同通过throws声明了抛出异常,然后在main()方法中调用该方法,此时main()方法就知道divide()方法中抛出了异常,可以采用如下两种方式进行处理。
通过try-catch捕获异常并处理异常。
通过throws继续声明异常。如果调用者不知道如何处理该异常,可以继续通过throws声明异常,让上一级调用者处理异常。main()方法声明的异常将由Java虚拟机来处理。
示例七:在Java中使用throws声明抛出异常。

import java.util.InputMismatchException;
import java.util.Scanner;
public class num{
    public static void main(String[] args){
        try {
            divide();
        }catch (InputMismatchException e){
            System.out.println("被除数和除数必须是整数。");
        }catch (ArithmeticException e){
            System.out.println("整数不能为零。");
        }catch (Exception e){
            System.out.println("其他未知异常。");
        }finally {
            System.out.println("感谢使用本程序!");
        }
    }
    public static void divide()throws Exception{
    Scanner in = new Scanner(System.in);
            System.out.print("请输入被除数:");
                    int num1 = in.nextInt();
                    System.out.print("请输入除数:");
                    int num2 = in.nextInt();
                    System.out.println(num1 + "/" + num2 + "=" + num1 / num2);}
}

使用throw抛出异常

除了系统自动抛出异常外,在编程过程中,有些问题是系统无法自动发现并解决的,如年龄不在正常范围内,性别输入不是“男”或“女”等,此时需要程序员而不是系统来自行抛出异常,把问题交给调用者去解决。
在Java语言中,可以使用throw关键字来自行抛出异常。在下面的实例八的代码中抛出了一个异常,抛出异常的原因就在于当前环境无法解决参数问题,因此在方法内部通过throw抛出异常,把问题交给调用者去解决。
实例八:在Java中使用throw抛出异常。
使用throw抛出年龄异常。
需求说明:
在setAge(int age) 中对年龄进行判断,如果年龄介于1到100直接赋值,否则抛出异常。
在测试类中创建对象并调用setAge(int age)方法,使用try-catch捕获并处理异常。
在这里插入图片描述

public class Person {
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age)throws Exception {
       if(age<=100&&age>=0){
        this.age = age;}
        else {
           throw new Exception("年龄必须在0-100之间");
       }
    }
}
public class Text2 {
    public static void main(String[] args) {
        Person p=new Person();
        try{
            p.setAge(123);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

输出结果:
在这里插入图片描述
throw与throws区别:
在这里插入图片描述

自定义异常

当JDK中的异常类型不能满足程序的需要时,可以自定义异常类。使用自定义异常一般有如下几个步骤:
(1)定义异常类,并继承Exception或者RuntimeException。
(2)编写异常类的构造方法,并继承父类的实现。
示例九:使用自定义异常实现示例八。

public class WrongSexException extends RuntimeException{
    public WrongSexException(String sexx){
        super(sexx);
    }
}
public class Person {
    private int age;

    public int getAge() {
        return age;
    }
    public void setAge(int age)throws WrongSexException {
       if(age<=100&&age>=0){
        this.age = age;}
        else {
           throw new WrongSexException("性别错误");
       }
    }
}
public class Text2 {
    public static void main(String[] args) {
        Person p=new Person();
        try{
            p.setAge(123);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

输出结果:
在这里插入图片描述

异常处理原则

异常处理与性能
异常只能用于非正常情况
不要将过于庞大的代码块放在try中
在catch中指定具体的异常类型
需要对捕获的异常做处理

总结

Throwable
Error:错误(无法恢复的)
Exception:异常:处理之后能正常运行
确定会发生异常的情况:
Checked异常:提前处理
不确定:
运行期异常:RuntimeException,遇到了再解决
常见的异常类型:
算术异常:ArithmeticException
空指针异常:NullPointException
数组越界异常:ArrayIndexOutOfBoundsException
缩印越界异常:IndexOutBoundsException
类型转换异常:ClassCastException
输入类型不匹配:InputMismatchException
输入输出异常:IOException
SQl异常:SQLException
非法参数异常:IllegalArgumentException
数字格式化异常:NumberFormatException
未找到类的异常:ClassNotFoundException
异常处理:
try{
有可能发生问题的代码块;
}catch(有可能发生的异常类型 e){对异常的查看操作
}
try-catch块中存在return语句,是否还执行finally块? 如果执行,说出执行顺序
执行,return后面的
try-catch- finally块中, finally块唯一不执行的情况是什么?
强制中断,System.exit
throw和throws
throw:抛出,手动产生异常
必须在条件语句内
throws:声明该方法未处理的异常
RuntimeException:不一定要处理
Exception:一定要处理
自定义异常类的过程:
继承某个已知的异常类
有参构造super(message)调用父类的有参构造

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值