文章目录
前言
本文是对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()
如何取得异常对象的具体信息,常用的方法主要有两种:
- 取得异常描述信息:getMessage()
- 取得异常的堆栈信息(比较适合于程序调试阶段):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 关键字在使用上的几点区别如下:
- throw 关键字用在方法内部,只能用于抛出一种异常,用来抛出方法中的异常。
- 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