1、什么是异常,java提供异常处理机制有什么用?
- 什么是异常:程序执行过程中的不正常情况。
- 异常的作用:增强程序的
健壮性
。 -
public class ExceptionTest01 { public static void main(String[] args) { int a = 10; int b = 0; // 实际上JVM在执行到此处的时候,会new异常对象:new ArithmeticException("/ by zero"); // 并且JVM将new的异常对象抛出,打印输出信息到控制台了。 int c = a / b; System.out.println(a + "/" + b + "=" + c); // 此处运行也会创建一个:ArithmeticException类型的异常对象。 System.out.println(100 / 0); } }
2、java语言中异常是以什么形式存在的呢?
异常在java中以
类
的形式存在,每一个 异常类 都可以创建 异常对象。 -
public class ExceptionTest02 { public static void main(String[] args) { // 通过“异常类”实例化“异常对象” NumberFormatException nfe = new NumberFormatException("数字格式化异常!"); // java.lang.NumberFormatException: 数字格式化异常! System.out.println(nfe); } }
3、异常继承结构图
Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错,因此得名编译时异常。)。
RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不管,都行。)
4、异常的分类
异常分为 编译时异常 和 运行时异常。所有异常都是在 运行阶段 发生的。因为只有程序运行阶段才可以 new对象。
因为异常的发生就是 new异常对象。
4.1编译时异常因为什么而得名?
因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错,因此得名。4.2 编译时异常和运行时异常的区别?
编译时异常一般发生的概率 比较高。
运行时异常一般发生的概率 比较低。
编译时异常发生概率较高,需要在运行之前对其进行 预处理。
运行时异常发生概率较低,没必要提前进行预处理。
4.3编译时异常和运行时异常别称
编译时异常
受检异常:CheckedException
受控异常
运行时异常
未受检异常:UnCheckedException
非受控异常
1、补充:
public class ExceptionTest03 { public static void main(String[] args) { System.out.println(100 / 0); // 这里的HelloWorld没有输出,没有执行。 System.out.println("Hello World!"); } }
程序执行到System.out.println(100 / 0);
此处发生了 ArithmeticException 异常,底层 new 了一个ArithmeticException异常对象,然后抛出了。
由于是 main方法 调用了100 / 0,所以这个异常ArithmeticException抛给了main方法。
main方法没有处理,将这个异常自动抛给了 JVM。JVM最终终止程序的执行。此时System.out.println("Hello World!");并不会执行。
注意:
ArithmeticException 继承 RuntimeException,属于 运行时异常。在编写程序阶段不需要对这种异常进行预先的处理。
public class ExceptionTest04 { public static void main(String[] args) { // main方法中调用doSome()方法 // 因为doSome()方法声明位置上有:throws ClassNotFoundException // 我们在调用doSome()方法的时候必须对这种异常进行预先的处理。 // 如果不处理,编译器就报错。 //编译器报错信息: Unhandled exception: java.lang.ClassNotFoundException doSome(); } /** * doSome方法在方法声明的位置上使用了:throws ClassNotFoundException * 这个代码表示doSome()方法在执行过程中,有可能会出现ClassNotFoundException异常。 * 叫做类没找到异常。这个异常直接父类是:Exception,所以ClassNotFoundException属于编译时异常。 * @throws ClassNotFoundException */ public static void doSome() throws ClassNotFoundException{ System.out.println("doSome!!!!"); } }
5、异常的处理方式
5.1 throws
在方法声明的位置上使用 throws 关键字抛出,谁调用我这个方法,我就抛给谁。抛给 调用者 来处理。这种处理异常的态度:上报。
5.2 try…catch
这个异常不会上报,自己把这个事儿处理了。
异常抛到此处为止,不再上抛了。注意:
只要异常没有捕捉,采用上报的方式,此方法的 后续代码不会执行。
try语句块中的某一行出现异常,该行 后面的代码不会执行。
try…catch捕捉异常之后,后续代码可以执行。
private static void m1() throws FileNotFoundException { System.out.println("m1 begin"); m2(); // 以上代码出异常,这里是无法执行的。 System.out.println("m1 over"); }
try { m1(); // m1方法出异常,下面代码不执行。 System.out.println("hello world!");//不执行 } catch (FileNotFoundException e){ //异常处理 System.out.println("出异常了!!"); System.out.println(e); } System.out.println("hello world"); //会执行
注意:
异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式。
一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM。JVM只有终止。
一般main方法中的异常建议使用try…catch进行捕捉。try { } catch (ClassNotFoundException e) { e.printStackTrace(); }
这个分支中可以使用e引用,
e引用
保存的内存地址是那个new出来异常对象的内存地址
。
6、在以后开发中,处理编译时异常,应该上报还是捕捉呢?
如果希望调用者来处理,选择throws上报。
其它情况使用捕捉的方式。
7、深入try…catch
catch后面的小括号中的类型可以是 具体的异常类型,也可以是该异常类型的 父类型。
catch可以写多个。建议catch的时候,精确的一个一个处理。这样有利于程序的调试。
catch写多个的时候,从上到下,必须遵守 从小到大。