Java异常知识点总结


前言

本文是对Java SE异常知识进行复习总结。(知识点很简单,但不完全面向小白哦!)

提示:以下是本篇文章正文内容,下面案例可供参考

一、异常的基本概念:

什么是异常,在程序运行过程中出现的错误,称为异常

public class ExceptionTest01 { 
 
 public static void main(String[] args) { 
 int i1 = 100; 
 int i2 = 0; 
 
 int i3 = i1/i2; 
 
 System.out.println(i3); 
 } 
}

在这里插入图片描述没有正确输出,抛出了被 0 除异常

通过以上示例,我们看到 java 给我们提供了这样一个体系结构,当出现问题的时候,它会告
诉我们,并且把错误的详细信息也告诉我们了,这就是异常的体系结构,这样我们的程序更健
壮。从上面大家还可以看到,java 异常都是类,在异常类中会携带一些信息给我们,我们可以通过这个类把信息取出来

二、异常的分类

1.异常的层次结构:

在这里插入图片描述

2.异常的分类:

异常主要分为:错误、一般性异常(受控异常)、运行期异常(非受控异常)

错误:如果应用程序出现了 Error,那么将无法恢复,只能重新启动应用程序,最典型的

Error 的异常是:OutOfMemoryError

受控异常:出现了这种异常必须显示的处理,不显示处理 java 程序将无法编译通过。

非受控异常:此种异常可以不用显示的处理,例如被 0 除异常,java 没有要求我们一定要处理

3.try、catch和finally

异常的捕获和处理需要采用 try 和 catch 来处理,具体格式如下:

try { 
 
}catch(OneException e) { 
 
}catch(TwoException e) { 
 
}finally { 
 
} 

try 中包含了可能产生异常的代码

try 后面是 catch,catch 可以有一个或多个,catch 中是需要捕获的异常

当 try 中的代码出现异常时,出现异常下面的代码不会执行,马上会跳转到相应的catch 语句块中,如果没有异常不会跳转到 catch 中

finally 表示,不管是出现异常,还是没有出现异常,finally 里的代码都执行,finally 和 catch可以分开使用,但 finally 必须和 try 一块使用,如下格式使用 finally 也是正确的

try { 
 
}finally { 
 
} 

【示例代码】

public class ExceptionTest02 { 
 
 public static void main(String[] args) { 
 	int i1 = 100; 
 	int i2 = 0; 
 	//try 里是出现异常的代码 
 	//不出现异常的代码最好不要放到 try 作用 
 	try { 
 
 	//当出现被 0 除异常,程序流程会执行到“catch(ArithmeticExceptionae)”语句 
 	//被 0 除表达式以下的语句永远不会执行 

 	int i3 = i1/i2; 
 
 	//永远不会执行 

 	System.out.println(i3); 
 
 	//采用 catch 可以拦截异常 
 	//ae 代表了一个 ArithmeticException 类型的局部变量 
	//采用 ae 主要是来接收 java 异常体系给我们 new 的 ArithmeticException对象 
 	//采用 ae 可以拿到更详细的异常信息 
 	}catch(ArithmeticException ae) { 
 		System.out.println("被 0 除了"); 
 	} 
 } 
}  

4.getMessage 和 printStackTrace()

如何取得异常对象的具体信息,常用的方法主要有两种:

  1. 取得异常描述信息:getMessage()
  2. 取得异常的堆栈信息(比较适合于程序调试阶段):printStackTrace();

【代码示例】

public class ExceptionTest03 { 
 	public static void main(String[] args) { 
 		int i1 = 100; 
 		int i2 = 0; 
 		try { 
 			int i3 = i1/i2; 
 			System.out.println(i3); 
 		}catch(ArithmeticException ae) { 
 		//ae 是一个引用,它指向了堆中的 ArithmeticException 
 		//通过 getMessage 可以得到异常的描述信息 
 		System.out.println(ae.getMessage()); 
 		} 
 	} 
} 

在这里插入图片描述【代码示例】

public class ExceptionTest04 { 
 	public static void main(String[] args) { 
 		method1(); 
 	} 
 
 	private static void method1() { 
 		method2(); 
 	} 
 	private static void method2() { 
 		int i1 = 100; 
 		int i2 = 0; 
 		try { 
 			int i3 = i1/i2; 
 			System.out.println(i3); 
 		}catch(ArithmeticException ae) { 
 		//ae 是一个引用,它指向了堆中的 ArithmeticException 
 		//通过 printStackTrace 可以打印栈结构 
 		ae.printStackTrace(); 
 		} 
 	} 
} 

在这里插入图片描述

5.受控异常:

受控异常在编译阶段必须进行处理,否则编译不通过。

/*
以下代码报错的原因是什么?
    因为doSome()方法声明位置上使用了:throws ClassNotFoundException
    而ClassNotFoundException是编译时异常。必须编写代码时处理,没有处理
    编译器报错。
 */
public class ExceptionTest04 {
    public static void main(String[] args) {
        // main方法中调用doSome()方法
        // 因为doSome()方法声明位置上有:throws ClassNotFoundException
        // 我们在调用doSome()方法的时候必须对这种异常进行预先的处理。
        // 如果不处理,编译器就报错。
        //编译器报错信息: Unhandled exception: java.lang.ClassNotFoundException
        //doSome();

        try {
            doSome();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            System.out.println("aaaa");
        }
    }

    /**
     * doSome方法在方法声明的位置上使用了:throws ClassNotFoundException
     * 这个代码表示doSome()方法在执行过程中,有可能会出现ClassNotFoundException异常。
     * 虽然没说一定会出现ClassNotFoundException异常,但是我们在调用这个方法的时候也得做预先处理,
     * 叫做类没找到异常。这个异常直接父类是:Exception,所以ClassNotFoundException属于编译时异常。
     * @throws ClassNotFoundException
     */
    public static void doSome() throws ClassNotFoundException{
        System.out.println("doSome!!!!");
    }
}

6.finally关键字:

finally 在任何情况下都会执行(除了退出虚拟机,System.exit(0);),通常在 finally 里关闭资源

/*
关于try..catch中的finally子句:
    1、在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。
        finally子句必须和try一起出现,不能单独编写。

    2、finally语句通常使用在哪些情况下呢?
        通常在finally语句块中完成资源的释放/关闭。
        因为finally中的代码比较有保障。
        即使try语句块中的代码出现异常,finally中代码也会正常执行。
 */
public class ExceptionTest10 {
    public static void main(String[] args) {
        FileInputStream fis = null; // 声明位置放到try外面。这样在finally中才能用。
        try {
            // 创建输入流对象
            fis = new FileInputStream("D:\\course\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
            // 开始读文件....

            String s = null;
            // 这里一定会出现空指针异常!
            s.toString();
            System.out.println("hello world!");

            // 流使用完需要关闭,因为流是占用资源的。
            // 即使以上程序出现异常,流也必须要关闭!
            // 放在这里有可能流关不了。
            //fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch(IOException e){
            e.printStackTrace();
        } catch(NullPointerException e) {
            e.printStackTrace();
        } finally {
            System.out.println("hello 浩克!");
            // 流的关闭放在这里比较保险。
            // finally中的代码是一定会执行的。
            // 即使try中出现了异常!
            if (fis != null) { // 避免空指针异常!
                try {
                    // close()方法有异常,采用捕捉的方式。
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        System.out.println("hello kitty!");

    }
}

final,finally,finalize区别:

final 关键字
    final修饰的类无法继承
    final修饰的方法无法覆盖
    final修饰的变量不能重新赋值。
finally 关键字
    和try一起联合使用。
    finally语句块中的代码是必须执行的。

finalize 标识符  
    是一个Object类中的方法名。作用:在对象回收前做一些清扫工作
    这个方法是由垃圾回收器GC负责调用的。

7.如何声明异常

在方法定义处采用 throws 声明异常,如果声明的异常为受控异常,那么调用方法必须处理此异常
【示例代码】,声明受控异常

import java.io.*; 
 
public class ExceptionTest13 { 
 	public static void main(String[] args) 
 	//throws FileNotFoundException, IOException { //可以在此声明异常,这样就交给 java 虚拟机处理了,不建议这样使用 
 	throws Exception { //可以采用此种方式声明异常,因为 Exception 是两个异常的父类 
 /* 
 //分别处理各个异常 
 	try { 
 		readFile(); 
 	}catch(FileNotFoundException e) { 
 		e.printStackTrace(); 
 	}catch(IOException e) { 
 		e.printStackTrace(); 
 	} 
 */ 
 	//可以采用如下方式处理异常 
 	//因为 Exception 是 FileNotFoundException 和 IOException 的父类 
 	//但是一般不建议采用如下方案处理异常,粒度太粗了,异常信息 
 	//不明确 
 /* 

 	try { 
 		readFile(); 
 	}catch(Exception e) { 
 		e.printStackTrace(); 
 	} 
 */ 
 		readFile(); 
 } 
 	private static void readFile() throws FileNotFoundException,IOException { //声明异常,声明后调用者必须
处理 

 		FileInputStream fis = null; 
 		try { 
 			fis = new FileInputStream("test.txt"); 
 	//}catch(FileNotFoundException e) { 
 	// e.printStackTrace(); 
 		}finally { 
 	//try { 
 		fis.close(); 
 //}catch(IOException e) { 
 // e.printStackTrace(); 
 //} 
 	} 
 	} 
} 

【示例代码】,声明非受控异常

public class ExceptionTest14 { 
 	public static void main(String[] args) { 
 		//不需要使用 try...catch..,因为声明的是非受控异常 

 		//method1(); 
 
 		//也可以拦截非受控异常 

 		try { 
 			method1(); 
 		}catch(ArithmeticException e) { 
 			e.printStackTrace(); 
 		} 
 } 
 //可以声明非受控异常 
 	private static void method1() throws ArithmeticException { 
 		int i1 = 100; 
		int i2 = 0; 
 	//try { 
 		int i3 = i1/i2; 
 		System.out.println(i3); 
 /* 
 	}catch(ArithmeticException ae) { 
 		ae.printStackTrace(); 
 	} 
 */ 
 	} 
} 

8.如何手动抛出异常

【实例代码】

public class Test08 {

    public static void main(String[] args) {
        int ret = method1(1000, 10);
        if (ret == -1) {
            System.out.println("除数为 0");
        }
        if (ret == -2) {
            System.out.println("被除数必须为 1~100 之间的数据");
        }
        if (ret == 1) {
            System.out.println("正确");
        }
        //此种方式的异常处理,完全依赖于程序的返回 
        //另外异常处理和程序逻辑混在一起,不好管理 
        //异常是非常,程序语句应该具有一套完成的异常处理体系 

    }

    private static int method1(int value1, int value2){
        if (value2 == 0) {
            return -1;
        }
        if (!(value1 >0 && value1<=100)) {
            return -2;
        }
        int value3 = value1/value2;
        System.out.println("value3=" + value3);
        return 1;
    }
}

辨析:throws 关键字和 throw 关键字在使用上的几点区别如下:

  1. throw 关键字用在方法内部,只能用于抛出一种异常,用来抛出方法中的异常。
  2. ​throws 关键字用在方法声明上,可以抛出多个异常,用来标识该方法可能抛出的异常列表。一个方法用 throws
    标识了可能抛出的异 常列表,调用该方法的方法中必须包含可处理异常的代码,否则也要在方法签名中用 throws 关键字声明相应的异常。

三:如何自定义异常

自定义异常通常继承于 Exception 或 RuntimeException,到底继承那个应该看具体情况来定
【实例代码】

/*
1、SUN提供的JDK内置的异常肯定是不够的用的。在实际的开发中,有很多业务,
这些业务出现异常之后,JDK中都是没有的。和业务挂钩的。那么异常类我们
程序员可以自己定义吗?
    可以。

2、Java中怎么自定义异常呢?
    两步:
        第一步:编写一个类继承Exception或者RuntimeException.
        第二步:提供两个构造方法,一个无参数的,一个带有String参数的。

    死记硬背。
 */
public class MyException extends Exception{ // 编译时异常

    public MyException() {
    }

    public MyException(String message) {
        super(message);
    }

    public static void main(String[] args) {
        MyException m = new MyException("aaa");
        System.out.println(m.getMessage());//aaa
        m.printStackTrace();
    }
}

/*
public class MyException extends RuntimeException{ // 运行时异常

}
 */

四:方法覆盖与异常:

重写的方法不能抛出比原方法更大更宽泛的异常,可以抛出原方法的子异常。

import java.io.*;
 
public class Father {
	public void father_function() throws IOException {
		new File("a.txt");
	}
}
 
class Son extends Father {
	@Override
	public void father_function() throws Exception {
		new File("b.txt");
	}
}
 
class Test {
	public static void main(String[] args) {
		Father fs = new Son();
		try {
			fs.father_function();
		}catch (IOException ie) {
			System.out.println("发生了异常");
		}
	}
}

1、在java多态机制中,对象引用fs在编译时期是属于父类类型也即Father类型,但是在运行时fs属于子类类型,也就是Son类型

2、也就是说在编译的时候,编译器发现catch中的IOException完全能将父类方法中抛出的异常捕获,因此编译通过,但是在运 行时期,由于fs变成了子类类型,子类重写的方法抛出的异常是Exception,显然IOException不能捕获这个比它更大的异 常,因此在运行时期也就出现失败

总结:这个示例也就演示了一个道理,在java中,子类重写父类的方法时,子类如果选择抛出异常,那么抛出的异常类型不能大于父类的异常类型


五:常见异常类型总结–熟记:

1.常见的 RuntimeException 有哪些?

ClassCastException(类转换异常)

IndexOutOfBoundsException(数组越界)

NullPointerException(空指针)

2. 常见的编译时异常有哪些:

1.FileNotFoundException
2.ClassNotFoundException
3.IOException

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JH3073

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

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

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

打赏作者

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

抵扣说明:

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

余额充值