java中的程序异常处理

1、什么是异常

指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。

在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。

异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行

2、java中的异常机制

如果某个方法不能按照正常的途径完成任务,就可以通过另一种路径退出方法。在这种情况下 会抛出一个封装了错误信息的对象。此时,这个方法会立刻退出同时不返回任何值。另外,调用 这个方法的其他代码也无法继续执行,异常处理机制会将代码执行交给异常处理器。

java中的异常体系如下

在 Java 中,所有的异常都有⼀个共同的祖先 java.lang 包中的 Throwable 类。 Throwable 类有两 个重要的⼦类:

Exception 又有两个分支,一个是运行时异常 RuntimeException , 一个是 ckedException。 RuntimeException 如 : NullPointerException 、 ClassCastException ; 一 个 是 检 查 异 常 CheckedException,如 I/O 错误导致的 IOException、SQLException。 RuntimeException 是那些可 能在 Java 虚拟机正常运行期间抛出的异常的超类。 如果出现 RuntimeException,那么一定是程序员的 错误.

检查异常 CheckedException:一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强制程序 去捕获此类异常,即会出现要求你把这段可能出现异常的程序进行 try catch,该类异常一般包括几个方 面:

1. 试图在文件尾部读取数据

2. 试图打开一个错误格式的 URL

3. 试图根据给定的字符串查找 class 对象,而这个字符串表示的类并不存在

Error : Error 属于程序⽆法处理的错误 ,我们没办法通过 catch 来进⾏捕获不建议通过 catch 捕获 。例如 Java 虚拟机运⾏错误( Virtual MachineError )、虚拟机内存不够错误 ( OutOfMemoryError )、类定义错误( NoClassDefFoundError )等 。这些异常发⽣时,Java 虚拟 机(JVM)⼀般会选择线程终⽌

异常的父类是 java.lang.Throwable ,Throwable中的常用方法 

//打印异常的详细情况 包含异常的类型,异常原因、还包括异常出现的位置,在开发和调试阶段,都得使用此方法
public void printStackTrace()
//获取异常信息 提示给用户的时候,只提示错误原因
public void getMessage()
//获取异常类型和异常信息
public String toString()

其下有两个子类:java.lang.Error与 java.lang.Exception 

2.1、Error

严重错误Error,无法通过处理的错误,只能事先避免,好比绝症,最常见的就是VirtualMachineError,它有两个经典的子类:StackOverflowError、OutOfMemoryError。

public class Test {
    public void test(){
        //StackOverflowError 栈溢出异常
        test();
    }
    public void test1(){
        //OutOfMemoryError 堆溢出异常
        int[] arr = new int[Integer.MAX_VALUE];
    }
}

2.1、Exception

表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的,分为运行时异常和编译时异常

运行时异常(非受检异常,RuntimeException及其子类)

public static void main(String[] args) {
        //这种写程序时候不报错,但是编译完运行的时候抛异常的就是运行时异常
        System.out.println(10/0);
    }

RuntimeException类常见的异常子类有:

1. ArithmeticException(试图除数为0时)

2. NullPointerException(当程序访问一个空对象的成员变量或方法,访问一个空数组的成员时发生。)

3. ClassCastException

4. ArrayIndexOutOfBoundsException访问的元素下表超过数组长度 分析jvm是如何处理异常的过程

5. NumberFormatException数字格式异常!

编译异常(受检异常)

指的是那些必须处理的异常(运行之前程序就报错)

    public static void main(String[] args) {
        //这种写代码的时候就报错不能编译的就是编译异常
        System.out.println(a);
       try {
           //这里必须使用try-catch处理的是也是编译时异常
           FileInputStream fileInputStream = new FileInputStream("d:/test.txt");
       }catch (Exception e){
           e.printStackTrace();
       }
    }

3、异常产生过程分析

4、异常处理

在Java应用中,异常的处理机制分为声明异常抛出异常捕获异常

可以根据下图来选择是捕获异常,声明异常还是抛出异常

4.1、捕获异常

try{
	......	//可能产生异常的代码
}
catch( 异常类型1 e ){
	......	//当产生异常类型1型异常时的处置措施
}
catch( 异常类型2 e ){
	...... 	//当产生异常类型2型异常时的处置措施
}  
finally{
	...... //无论是否发生异常,都无条件执行的语句
} 

1、整体运行流程
如果在程序运行时,try块中的代码没有发生异常,那么catch所有的分支都不执行。
如果在程序运行时,try块中的代码发生了异常,根据异常对象的类型,将从上到下选择第一个匹配的catch分支执行。此时try中发生异常的语句下面的代码将不执行,而整个try…catch之后的代码可以继续运行。
如果在程序运行时,try块中的代码发生了异常,但是所有catch分支都无法匹配(捕获)这个异常,那么JVM将会终止当前方法的执行,并把异常对象“抛”给调用者。如果调用者不处理,程序就挂了

2、try
捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的业务逻辑代码放在try语句块中。

3、catch
catch分支,分为两个部分,catch()中编写异常类型和异常参数名,{}中编写如果发生了这个异常,要做什么处理的代码。

如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。

比如:可以用ArithmeticException类作为参数的地方,就可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常,如NullPointerException(catch中的语句将不会执行)。

每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。

如果有多个catch分支,并且多个异常类型有父子类关系,必须保证小的子异常类型在上,大的父异常类型在下。否则,报错。

catch中常用异常处理的方式

a、public String getMessage():获取异常的描述信息,返回字符串

b、public void printStackTrace():打印异常的跟踪栈信息并输出到控制台。包含了异常的类型、异常的原因、还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace()。

 4、finally

因为异常会引发程序跳转,从而会导致有些语句执行不到。而程序中有一些特定的代码无论异常是否发生,都需要执行。例如,数据库连接、输入流输出流、Socket连接、Lock锁的关闭等,这样的代码通常就会放到finally块中。所以,我们通常将一定要被执行的代码声明在finally中。

唯一的例外,使用 System.exit(0) 来终止当前正在运行的 Java 虚拟机。
不论在try代码块中是否发生了异常事件,catch语句是否执行,catch语句是否有异常,catch语句中是否有return,finally块中的语句都会被执行。

finally语句和catch语句是可选的,但finally不能单独使用。
try{
     
}finally{
    
} 

案例1:关闭资源

package com.atguigu.keyword;

import java.util.InputMismatchException;
import java.util.Scanner;

public class TestFinally {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.print("请输入第一个整数:");
            int a = input.nextInt();
            System.out.print("请输入第二个整数:");
            int b = input.nextInt();
            int result = a/b;
            System.out.println(a + "/" + b +"=" + result);
        } catch (InputMismatchException e) {
            System.out.println("数字格式不正确,请输入两个整数");
        }catch (ArithmeticException e){
            System.out.println("第二个整数不能为0");
        } finally {
            System.out.println("程序结束,释放资源");
            input.close();
        }
    }
    
    @Test
    public void test1(){
        FileInputStream fis = null;
        try{
            File file = new File("hello1.txt");
            fis = new FileInputStream(file);//FileNotFoundException
            int b = fis.read();//IOException
            while(b != -1){
                System.out.print((char)b);
                b = fis.read();//IOException
            }

        }catch(IOException e){
            e.printStackTrace();
        }finally{
            try {
                if(fis != null)
                    fis.close();//IOException
            } catch (IOException e) {
                e.printStackTrace();
            }	
        }
    }
}

关于try-catch使用 推荐文章
java 异常 try catch finally中return的影响详解_zzhongcy的博客-CSDN博客

4.2、抛出异常

如果你觉得解决不了某些异常问题,且不需要调用者处理,那么你可以抛出异常。 throw关键字作用是 在方法内部抛出一个Throwable类型的异常。任何Java代码都可以通过throw语句抛出异常。

    public static void main(String[] args) {
        test();
    }

    public static void test() {
       if(1==2){
           //可以throw一个运行时异常
           throw  new RuntimeException();
       }else if (1>2){
           //throw一个自定义异常
           throw new MyException();
       }else {
           //可以throw一个具体的异常
           throw new IndexOutOfBoundsException();
       }
    }

有时我们会从 catch 中抛出一个异常,目的是为了改变异常的类型。多用于在多系统集成时,当某个子 系统故障,异常类型可能有多种,可以用统一的异常类型向外暴露,不需暴露太多内部异常细节

4.3、声明异常

通常 应该捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下 去。传递异常可以在方法签名处使用 throws 关键字声明可能会抛出的异常

    public int div(int a,int b) throws Exception {
       return a/b;
    }

throws后面可以写多个异常类,用逗号隔开。如果方法内通过throw抛出了编译时异常,而没有捕获处理,那么必须通过throws进行声明,让调用者去处理,如下


    public static void main(String[] args) throws FileNotFoundException {
        test();
    }

    public static void test() throws FileNotFoundException {
       if(1==2){
           //可以throw一个运行时异常
           throw  new FileNotFoundException();
       }
    }

6、自定义异常

1. 自定义一个编译期异常: 自定义类 并继承于 java.lang.Exception 。

2. 自定义一个运行时期的异常类:自定义类 并继承于 java.lang.RuntimeException

习惯上,定义一个异常类应包含两个构造函数,一个无参构造函数和一个带有详 细描述信息的构造函数(Throwable 的 toString 方法会打印这些详细信息,调试时很有用)

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序三两行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值