Java SE 6th day ——Exception

本文深入浅出地介绍了Java中的异常处理机制,包括异常的基本概念、异常处理语法、异常处理流程等核心内容。并通过实例展示了try...catch...finally、throw、throws等关键字的应用,帮助读者掌握异常处理的标准模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(材料源于网络)

JavaSE 6th day

——Exception

1、本次课程知识点

1、认识异常及异常的默认处理操作;

2、异常处理语句的使用;

3、throw和throws关键字的作用;

4、异常处理的标准操作格式;

5、自定义异常和assert关键字的使用。

2、具体内容

2.1 认识异常(理解)

异常是导致程序中断执行的一种指令流,即:程序之中一旦产生了异常之后,程序在默认情况下将中断执行。

范例:观察如下的程序:

public class Demo {

    public static void main(String args[]) {

       int x=10;

       int y=0;

       System.out.println("========Start of the calculation========");

       int result=x/y;

       System.out.println("Result of the calculation:"+result);

       System.out.println("========End of the calculation========");

    }

}

此时,由于被除数是0,所以现在程序运行之后的结果是:

现在很明显,是在异常出现之后的语句都不再执行了,通过程序可以发现,异常出现之后,程序将导致运行,即中断执行了。

额外:计算机的两大杀手

对于计算机而言,最导致的两个操作:断电、除以0;

2.2 异常处理语法(重点

如果现在希望发生异常之后,程序依然可以正确的执行完毕,则可以采用如下的异常处理格式完成:

try{

         //可能出现异常的语句

}[catch(异常类 异常类对象){

         //异常的处理

}[catch(异常类 异常类对象){

         //异常的处理

}[catch(异常类 异常类对象){

         //异常的处理

}……]]]

[finally{

         //不管是否有异常都要执行此代码

}]

范例:使用try……catch处理异常

public class Demo {

    public static void main(String args[]) {

       int x=10;

       int y=0;

       System.out.println("========Start of the calculation========");

       try{

           int result=x/y;

           System.out.println("Result of the calculation:"+result);

       }catch(ArithmeticException e){ //此处捕获的是算术异常

           System.out.println(e);

       }

       System.out.println("========End of the calculation========");

    }

}

此时程序的输出:

==================Start of the calculation==================

java.lang.ArithmeticException: / by zero

==================End of the calculation==================

通过输出可以发现,现在的程序可以正常的执行完毕了,而且可以发现,在try语句之中,捕获异常之后,异常代码之后的语句将不再执行了,如果现在没有异常发生,则不再执行catch语句中的操作。

现在的异常输出直接采用了输出异常对象的方式完成,而这种异常的信息并不是完整的,所以很多时候都会直接调用异常类中的printStackTrace()方法打印异常信息;

public class Demo {

    public static void main(String args[]) {

       int x = 10;

       int y = 1;

       System.out.println("========Start of the calculation========");

       try {

           int result = x / y;

           System.out.println("Result of the calculation:" + result);

       } catch (ArithmeticException e) {// 此处捕获的是算术异常

           ae.printStackTrace();//直接输出对象

       }finally//异常的出口

           System.out.println("Execute the procedure though the Exception!");

       }

       System.out.println("========End of the calculation========");

    }

}

========Start of the calculation========

Result of the calculation:10

Execute the procedure though the Exception!

========End of the calculation========

但是写到这里也有一个问题了,抛开异常处理程序不谈,可以发现最后的输出语句也是无论是否有异常都会执行,实际上对于finally程序有特定的使用语法,而且是要结合之后的异常处理的标准格式来讲的。

但是随着java的发展,除了以上的两种格式之外,也存在了另外一种格式:

public class Demo {

    public static void main(String args[]) {

       int x = 10;

       int y = 1;

       System.out.println("========Start of the calculation========");

       try {

           int result = x / y;

           System.out.println("Result of the calculation:" + result);

       } finally {// 异常的出口

           System.out.println("Execute the procedure though the Exception!");

       }

       System.out.println("========End of the calculation========");

    }

}

即在原来的基础上删掉了catch关键字,但这种写法建议绝对不要使用!

在之前的程序之中,已经进行一个异常的处理,如果现在要把程序扩充一下,例如:现在希望两个计算的数字可以由初始化参数指定,所以现在的代码修改如下:

public class Demo {

    public static void main(String args[]) {

       int x = 0;

       int y = 0;

       System.out.println("========Start of the calculation========");

       try {

           x = Integer.parseInt(args[0]); // 接收第一个数字

           y = Integer.parseInt(args[1]); // 接收第二个数字

           int result = x / y;

           System.out.println("Result of the calculation:" + result);

       } catch (ArithmeticException e) {// 此处捕获的是算术异常

           e.printStackTrace();// 直接输出对象

       } finally { // 异常的出口

           System.out.println("Execute the procedure though the Exception!");

       }

       System.out.println("========End of the calculation========");

    }

}

但是此时一些新的问题也来了:

问题一:如果用户在执行程序的时候没有输入参数:

问题二:如果用户输入的参数不是数字:

问题三:输入的除数是0:

通过以上的程序分析可以发现,每种异常都应该有每种异常的类型,而之前的程序所有的异常都只按照了一种异常处理,那么这之外的异常就无法处理了,所以此时可以在try语句后增加多个catch。

public class Demo {

    public static void main(String args[]) {

       int x = 0;

       int y = 0;

       System.out.println("========Start of the calculation========");

       try {

           x = Integer.parseInt(args[0]); // 接收第一个数字

           y = Integer.parseInt(args[1]); // 接收第二个数字

           int result = x / y;

           System.out.println("Result of the calculation:" + result);

       } catch (ArithmeticException e) {// 此处捕获的是算术异常

           e.printStackTrace();// 直接输出对象

       } catch(ArrayIndexOutOfBoundsException e){

           e.printStackTrace();

       }catch(NumberFormatException e){

           e.printStackTrace();

       }finally { // 异常的出口

           System.out.println("Execute the procedure though the Exception!");

       }

       System.out.println("========End of the calculation========");

    }

}

现在程序之中可以处理三个异常,但是程序写到这个地方一个问题就该出现了,以上所有的异常都是一个个实验出来的,那么并没有感觉到异常处理的方便,如果现在是一段不熟悉的代码,你有可能花那么多的时间进行分析吗?

2.3 异常的处理流程(核心

如果现在要想简化异常的处理操作,那么就必须首先掌握异常的两大内容:继承结构、处理流程;

以“ArithmeticException”异常类为例,观察此类的继承结构:

可以发现ArithmeticException类的父类是Throwable,表示允许抛出的,在Throwable中有两个子类:

Error:表示的是JVM出错,即:程序还没有运行时所发生的错误,用户无法处理;

Exception:表示程序运行中发生的错误,用户可以处理;

一般情况下,所谓的异常处理异常指的是都是Exception的子类,那么按照之前所讲解的对象的转型操作而言,所有的子类对象都可以向父类自动转型,所以,那么如果现在要想简化异常的处理操作,则还要进行异常的处理流程分析。

1、在程序之中如果发生异常,则首先会有JVM自动的产生一个指定异常类的实例化对象;

2、此异常对象要被try语句所捕获,如果现在没有异常处理语句,则也交给JVM处理;

3、将此异常类的对象想方法参数传递那样,与每一个catch进行匹配,如果匹配成功,则使用catch进行处理,如果匹配不成功则向下继续匹配,如果都没有成功的则交给JVM采用默认的处理方式(程序中断);

4、当程序之中异常处理完毕之后,都会调用finally程序进行异常的出口收尾工作;

5、如果之后有其他语句,则继续执行;

通过以上的分析可以得出:所谓的异常出来实际上还是一个引用数据类型的操作流程,

所以按照子类对象自动向父类对象转型的技术要求,则可以直接使用Exception(异常的父类)进行全部异常的处理。

如果现在希望省事,可以利用Exception进行处理,但是由于Exception的捕获范围更大,所以这种捕获必须放在捕获范围小的异常之后,否则程序在编译时就会出现错误提示。

public class Demo {

    public static void main(String args[]) {

       int x = 0;

       int y = 0;

       System.out.println("========Start of the calculation========");

        try {

           x = Integer.parseInt(args[0]); // 接收第一个数字

           y = Integer.parseInt(args[1]); // 接收第二个数字

           int result = x / y;

           System.out.println("Result of the calculation:" + result);

       } catch (ArithmeticException e) {// 此处捕获的是算术异常

           e.printStackTrace();// 直接输出对象

       } catch (ArrayIndexOutOfBoundsException e) {

           e.printStackTrace();

       } catch (NumberFormatException e) {

           e.printStackTrace();

       }catch (Exception e) {

           e.printStackTrace();

       } finally {// 异常的出口

           System.out.println("Execute the procedure though the Exception!");

       }

       System.out.println("========End of the calculation========");

    }

}

但是,Exception肯定把所有的异常都包含了,所以现在实际上以上的程序,可以采用更简便的做法:

public class Demo {

    public static void main(String args[]) {

       int x = 0;

       int y = 0;

       System.out.println("========Start of the calculation========");

       try {

           x = Integer.parseInt(args[0]); // 接收第一个数字

           y = Integer.parseInt(args[1]); // 接收第二个数字

           int result = x / y;

           System.out.println("Result of the calculation:" + result);

       } catch (Exception e) {

           e.printStackTrace();

       } finally { // 异常的出口

           System.out.println("Execute the procedure though the Exception!");

       }

       System.out.println("========End of the calculation========");

    }

}

可是这种做法只适合于异常处理要求不高的开发环境下,如果现在开发之中要求每种异常都要分别进行处理的话,这种做法就不可取了,必须编写多个catch语句。

面试题:

1、请解释Error和Exception的求别:

Error:表示的是JVM出错,即:程序还没有运行时所发生的错误,用户无法处理;

Exception:表示程序运行中发生的错误,用户可以处理;

2、请解释异常处理的流程:

A、在程序之中如果发生异常,则首先会有JVM自动的产生一个指定异常类的实例化对象;

B、此异常对象要被try语句所捕获,如果现在没有异常处理语句,则也交给JVM处理;

C、将此异常类的对象想方法参数传递那样,与每一个catch进行匹配,如果匹配成功,则使用catch进行处理,如果匹配不成功则向下继续匹配,如果都没有成功的则交给JVM采用默认的处理方式(程序中断);

D、当程序之中异常处理完毕之后,都会调用finally程序进行异常的出口收尾工作;

E、如果之后有其他语句,则继续执行;

2.4 throws关键字(重点

throws关键字的主要功能是在方法定义上使用的,表示一个方法之中不处理异常,而交给程序的被调用处处理,实际上就属于一种问题的转移,即:原本是A的问题现在交给了B处理。

package course_2;

 

class MyMath {

    public static int div(int x,int y) throws Exception {//不再由方法处理

       return x / y;

    }

}

 

public class Demo {

    public static void main(String args[]) {

       try {

           System.out.println(MyMath.div(10, 0));

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

}

java.lang.ArithmeticException: / by zero

    at course_2.MyMath.div(Demo.java:6)

    at course_2.Demo.main(Demo.java:13)

实际上现在在主方法之中,也可以继续向上抛出异常,直接写上throws即可。

package course_2;

 

class MyMath {

    public static int div(int x,int y) throws Exception {//不再由方法处理

       return x / y;

    }

}

 

public class Demo {

    public static void main(String args[])throws Exception {

       MyMath m = new MyMath();

       System.out.println(m.div(10, 0));

    }

}

java.lang.ArithmeticException: / by zero

    at course_2.MyMath.div(Demo.java:5)

    at course_2.Demo.main(Demo.java:12)

主方法之上就是JVM了,所以如果在主方法上写了throws,则表示交给JVM进行处理(所以在程序主方法中就可以不写try……catch语句进行异常的捕获和处理了),而JVM的处理原则就是程序的中断执行,所以在开发之中,不要在main()方法上继续向上抛异常了。

2.5 throw关键字(重点

在之前的throws是在方法上定义的,而且在方法上抛出的异常也有可能就是由JVM自动抛出的,但是现在可以利用throw关键字手工的抛出一个异常。

package course_2;

 

publicclass Demo {

    public static void main(String args[])throws Exception {

       try {

           throw new Exception("抛着玩。");

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

}

java.lang.Exception:抛着玩。

    at course_2.Demo.main(Demo.java:6)

不理解,在开发之中躲异常还来不及呢,还往上招惹,不懂。请继续看一下范例。

范例:在方法中抛出异常。

public class Demo {

    public void throwException() throws Exception{

        System.out.println("throwException() strart.");

        throw new Exception("Evil exception!");

//      System.out.println(); //注意在抛出异常后是不能继续再写其他语句的。

    }

 

    public static void main(String args[]) {

        System.out.println("MAIN strat.");

        try {

            new Demo().throwException();

        } catch (Exception e) {

            System.out.println("Receipted EXCEPTION!");

            e.printStackTrace();

        }

        System.out.println("MAIN end.");

    }

}

MAIN strat.

throwException() strart.

Receipted EXCEPTION!

java.lang.Exception: Evil exception!

    at firstCourse.Demo.throwException(Demo.java:6)

    at firstCourse.Demo.main(Demo.java:13)

MAIN end.

笔记:和在main方法中抛出异常不同的是,在非main方法中抛出异常的话通常在这个方法中都会使用throws Exception把所长生的异常交给调用处处理,否则自定义的throw异常就没什么意义了,如“抛着完”这个例子。

面试题:请解释throwthrows的区别?

● throw表示人为的进行异常的抛出,手工抛出对象;

● throws是用于方法的声明上,表示一个方法不处理异常,而交给被调用处处理;

2.6异常处理的标准格式(最核心

现在学习完了:try……catch……finally、throw、throws等五个关键字,那么这五个关键字改如何应用呢?下面通过一个程序的分析完成。

例如,现在要求定义一个div()方法,此方法要求在计算开始和结束的时候有信息输出,而且如果出现了异常,则要求交给被调用处处理

package course_2;

 

class MyMath {

    public static int div(int x,int y) throws Exception {//不再由方法处理此处不加结果一样,因为本方法中使用try……catch语句

       System.out.println("*********计算开始*********");

       int result = 0;

       try {

           result = x / y;

       } catch (Exception e) {

           System.out.println(e);//如果把异常向上抛(throw e),则一般不再写此语句,此处为了测试所需

           throw e; // 把异常向上抛

           // 以上两条语句不能互换位置,否则在编译时就出错

       } finally {

           System.out.println("*********计算结束*********");

       }

       return result;    // 如果没有异常产生或“throw e”语句,此行代码都将执行!

//没有“throw e”情况下,会在div()方法处理完异常后,    //0返回到被调用处

    }

}

 

public class Demo {

    public static void main(String args[]) {

       try {

           System.out.println(MyMath.div(10, 0));

       } catch (Exception e) {

           System.out.println("主方法处理异常前");

           e.printStackTrace();

           System.out.println("主方法处理异常后");

       }

    }

}

*********计算开始*********

java.lang.ArithmeticException: / by zero

*********计算结束*********

主方法处理异常前

java.lang.ArithmeticException: / by zero

    at course_2.MyMath.div(Demo.java:8)

    at course_2.Demo.main(Demo.java:25)

主方法处理异常后

从程序中可以发现,通过合理的搭配程序完成了需要的功能,不过在MyMath类中div()方法是否会产生异常都会执行“计算结束”的语句。如果有异常产生则将异常交给调用处处理。本程序的具体执行流程如下图:

以上只是演示了一个基本的程序模型,而在日后的操作之中,可以把两个输出语句换成某些资源的打开和关闭操作。

注意:finally语句块的编写要求。

finally作为异常的统一出口,所以在此语句块的编写中尽可能不要出现像throw或return这样的语句,这样可以避免不必要的问题出现。

2.7 断言:assert(了解)

所谓的断言指的就是肯定某一个结果的返回值是正确的,如果最终此结果的返回值是错误的,则通过断言肯定会提示错误信息。

断言的定义格式:

assert boolean表达式;

assert boolean表达式:详细的信息;

如果以上的boolean表达式的结果为true,则什么错误信息都不会提示;如果为false,则会提示错误信息;如果没有声明详细的描述,则系统会使用默认的错误信息提示方式。

public class Demo {

    public static void main(String args[]) {

       int x = 10;

       assert x == 20;   //断言现在的x是20

       System.out.println(x);

    }

}

10

在正常情况下,断言是不会起左右的,而如果要想启动断言,则必须进行参数的配置:java -ea Demo

此时表示程序要进行断言的检查,那么默认情况下,断言的错误信息是由系统提供的,当然也可以由用户自己指定:

public class Demo {

    public static void main(String args[]) {

       int x = 10;

       assert x == 20:"x的内容不是20";//断言现在的x是20

       System.out.println(x);

    }

}

断言是在JDK1.4之后增加的,在开发之中也不会使用。

2.8 自定义异常类(了解)

在java之中已经为用户提供了大量的异常类的信息,但是很多时候用户往往希望可以定义一些异常,表示自己项目中所使用的异常类,那么在这种情况下就可以让一个类直接继承Exception类即可实现。

class MyException extends Exception{

    public MyException(String msg){

       super(msg);

    }

}

 

public class Demo{

    public static void main(String args[])throws Exception{

       throw new MyException("自定义异常类。");

    }

}

一般的开发之中,很少会用到此概念,但是做一些系统的架构设计的时候还是会用到的,例如以后的框架之中会有许多新的异常类型,实际上所有的异常类最简单的处理方式都是使用Exception。

2.9 RuntimeException(重点

下面首先来观察如下一段程序:

public class Demo {

    public static void main(String args[]) {

       int num = Integer.parseInt("100");// 字符串变为int

       System.out.println(num);

    }

}

100

现在的程序编译上没有任何的错误,但是下面观察一下parseInt()方法的定义:

public static int parseInt(String s)throws NumberFormatException

这个方法上使用了一个throws关键字抛出了异常,那么为什么程序中不去处理呢?

下面首先观察一下此异常的继承结构:

可以发现这个异常类是RuntimeException的子类,而在java之中,所有的RuntimeException的异常类可以根据用户的需要进行选择性的处理,不处理也不会有问题,但是一旦出错,则会由JVM默认处理。

面试题:请解释Exception和RuntimeException的区别,并列出几个常见的RuntimeException。

● Exception和RuntimeException的区别:Exception的异常必须处理,而RuntimeException的异常可以选择性处理;

● 常见的RuntimeException:NumberFormatException、ArithmeticException、NullPointerException、ClassCastException、ArrayIndexOutOfBoundsException;

3、总结

1、明确的理解异常处理的作用:保证程序的正常执行完毕;

2、异常处理的流程;

3、异常处理的标准格式:try……catch……finally、throws、throw的联合应用。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值