文章目录
一.异常概述
我们先看一个简单的demo.
package com.sdnu.project1;
import javax.xml.bind.SchemaOutputResolver;
/**
* @author Beyong
* @Description Exception
* @date 2021/05/22 10:18
*/
public class Demo1 {
public static void main(String[] args) {
int number1 = 1;
int number2 = 0;
System.out.println(number1/number2);
}
}
结果:
以上程序就是我们所说的异常,它是在我们程序运行过程中发生了不正常的情况。以上的程序异常被打印在屏幕上,使得我们可以有针对的进行修改代码,增强了程序的健壮性,实际上,上面程序的异常由我们的JVM所打印的。
二.Java中异常以类和对象的形式存在
我们通过查看官方jdk1.8,发现每一个异常都是一个类。
既然是类,那么它就可以new一个对象出来,于是我们以上面的例子测试一下
package com.sdnu.project1;
/**
* @author Beyong
* @Description demo2
* @date 2021/05/22 10:43
*/
public class Demo2 {
public static void main(String[] args) {
ArrayIndexOutOfBoundsException temp = new ArrayIndexOutOfBoundsException("kkk");
System.out.println(temp);
}
}
我们回到最开始的案例,实际上,当我们的JVM执行到System.out.println(number1/number2);
的时候,JVM会new一个对象出来,new ArithemeticException(" / by zero")
,然后由JVM在控制台中打印出来,当然这个是我们看不见的情况之下由我们的JVM默默帮我们去做的。
再次理解!!!
比如有一个着火异常(类为着火)
(下面都为实例对象)
-> 小明家着火
-> 小李家着火
-> 小张家着火
三.异常的继承
- Throwable为可抛出的
- Error异常,由JVM抛出,终止程序,而Exception可进行处理
- Exception的直接子类为编译时异常(注意时是RuntimeException以外的异常),必须在先进行处理,如果不处理,编译会报错,所以叫做编译时异常
- RuntimeException及它的子类为运行时异常。
四.编译时异常及运行时异常的区别
编译时异常发生概率较高,而运行时异常发生概率较低。
举个例子。
编译时异常就像我们出门前,我们就可以知道这个时候是否下雨,我们就可以提前准备雨伞,而运行时异常就像我们平时走在马路上,突然高空抛下一个香蕉皮。
编译时异常也叫做受检异常(CheckedException),或受控异常。
运行时异常也叫做未受检异常(UnCheckException),或非受控异常。
五.异常的两种解决方案
(一).在方法声明的位置使用throws抛出,抛给上一级,谁调用就抛给谁。
(二).使用try …catch语句进行捕捉。
举个例子:
我们因为工作失误导致公司损失100元,我们由两种解决方案,一种就是我们报给上一级领导,另一种是我们自己解决,别人不知道。
注意:(1)当我们的异常往上抛得时候,我们的上一级也是有两种解决方安。
(2)我们的异常由main()抛给JVM的时候,JVM会终止我们的程序。
六.编译时异常必须处理
我们观察下面的程序,我们在还没有运行的情况之下,就出现了异常,这是因为我们的ClassNotFoundException是编译异常,必须要首先进行处理。
package com.sdnu.project1;
/**
* @author Beyong
* @Description demo3
* @date 2021/05/22 21:22
*/
public class Demo3 {
public static void main(String[] args){
doSome();
}
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome");
}
}
七.处理异常
我们来使用我们之前所说的两种方法来处理我们的异常。
(一)向上抛出
package com.sdnu.project1;
/**
* @author Beyong
* @Description demo3
* @date 2021/05/22 21:22
*/
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException{
doSome();
}
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome");
}
}
(二)try … catch
package com.sdnu.project1;
/**
* @author Beyong
* @Description demo3
* @date 2021/05/22 21:22
*/
public class Demo3 {
public static void main(String[] args){
try{
doSome();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void doSome() throws ClassNotFoundException{
System.out.println("doSome");
}
}
八.try…catch深入理解
我们这里有一个新的例子:
package com.sdnu.project1;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/**
* @author Beyong
* @Description Demo5
* @date 2021/05/22 23:09
*/
public class Demo5 {
public static void main(String[] args) throws FileNotFoundException{
try{
m1();
} catch (FileNotFoundException e){
e.printStackTrace();
}
}
public static void m1() throws FileNotFoundException{
System.out.println("m1 begin");
m2();
System.out.println("m1 over");
}
public static void m2() throws FileNotFoundException {
System.out.println("m2 begin");
new FileInputStream("D:\\test1.txt");
System.out.println("m2 over");
}
}
我们重点来看一下try…catch
其中的FileNotFoundException e 指明了一个FileNotFoundException 类型的引用 e,它指向了我们的异常对象。
注意:FileInputStream的一个构造函数如下图所示,这个构造函数会抛出异常,而且是编译异常,所以我们必须进行处理。
我们通过官方的jdk文档查阅FileNotFoundException,发现它是我们前面所过的IOException的一个子类,实际上,我们在catch的()中不仅可以写该异常具体的异常类型,我们也可以写该异常的父类型。
package com.sdnu.project1;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* @author Beyong
* @Description Demo5
* @date 2021/05/22 23:09
*/
public class Demo5 {
public static void main(String[] args) {
try{
m1();
} catch ( FileNotFoundException e){
e.printStackTrace();
}
}
public static void m1() throws FileNotFoundException{
System.out.println("m1 begin");
m2();
System.out.println("m1 over");
}
public static void m2() throws FileNotFoundException {
System.out.println("m2 begin");
new FileInputStream("D:\\test1.txt");
System.out.println("m2 over");
}
}
改为FileInputStream的父类型:
我们也可以捕获多个异常,但是要注意捕获的异常子类型要在父类型之前。
九.上报还是捕获
只有一个原则:如果希望调用者处理,则选择上报。
十.异常对象的方法
(1)printStackTrace():取得异常的堆栈信息。
(2)getMessage():取得异常的描述信息。
十一.finally
finally关键字用来创建try后面要执行的代码,无论异常是否发生,都会执行。
我们通过更改文件路径,一次正确,一次故意写错误,也就是没有改文件,我们发现finally()都执行了。
当然,如果我们真的想退出,不执行finally,我们可以使用System.exit(0)来退出JVM
finally不执行了。
十二.自定义异常
方法:(1)一个类继承Exception或者RunTimeException
(2)该类提供两个构造方法,一个无参,一个带有String的参数
例子:
package com.sdnu.project1;
/**
* @author Beyong
* @Description Demo9
* @date 2021/05/23 08:48
*/
public class MyException extends Exception{
public MyException(){ }
public MyException(String Ex){
super(Ex);
}
}
package com.sdnu.project1;
/**
* @author Beyong
* @Description Demo8
* @date 2021/05/23 08:48
*/
public class Demo8 {
public static void main(String[] args) {
MyException temp = new MyException("hhh");
String str = temp.getMessage();
System.out.println(str);
temp.printStackTrace();
}
}
完整示例:
package com.sdnu.project1;
/**
* @author Beyong
* @Description Circle
* @date 2021/05/23 09:01
*/
public class Circle {
private int radius;
}
package com.sdnu.project1;
/**
* @author Beyong
* @Description Demo9
* @date 2021/05/23 08:48
*/
public class MyException extends Exception{
public MyException(){ }
public MyException(String Ex){
super(Ex);
}
}
package com.sdnu.project1;
import java.util.Scanner;
/**
* @author Beyong
* @Description Demo8
* @date 2021/05/23 08:48
*/
public class Demo8 {
public static void main(String[] args) {
System.out.println("Please input a radius of circle");
Scanner input = new Scanner(System.in);
int radius = input.nextInt();
try{
System.out.println(method(radius));
} catch (MyException ex) {
ex.getMessage();
ex.printStackTrace();
}
}
public static int method(int radius) throws MyException {
if(radius <= 0){
throw new MyException("半径异常");
}
return (int)(radius * radius * Math.PI);
}
}
作者:Beyong
出处:Beyong博客
github地址:https://github.com/beyong2019
本博客中未标明转载的文章归作者Beyong有,欢迎转载,但未经作者同意必须保留此段声明,且在文章明显位置给出原文连接,否则保留追究法律责任的权利。