异常的概述和分类
异常主要分为2种,分别是编译时异常和运行时异常
-
运行时异常:此种异常在编译时可以不用处理,例如被0除异常,java没有要求我们一定要处理。
-
编译时异常:有的地方也叫做一般性异常,出现了这种异常必须在程序里面进行处理,否则程序无法编译通过。
异常的处理 -
编写代码处理特定的异常,这些异常被处理之后,程序能够继续向下执行,比如后面要讲的try catch关键字。
-
将异常抛出或者不处理,这些最终都交给了jvm,jvm会将异常信息打印到控制台,比如后面要讲的throws关键字。
throws关键字声明异常
throws的作用是抛出异常,在方法声明的位置上使用throws关键字向上抛出异常,异常抛给了当前方法的调用者,即谁调用这个方法,谁就会得到这个异常
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class throwTest {
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
FileInputStream fis = new FileInputStream("file.txt");
//程序运行如果遇到了异常,它后面的代码就不再运行了。
System.out.println("上面出现异常后,这里就不执行了");
}
}
可以使用throws关键字将异常抛出,由于是jvm调用的main方法,所以这个异常抛给了jvm,jvm会将异常信息打印到控制台。当file.txt文件不存在的时候,就可以在控制台看到异常信息了。
- 有时在方法中可能会抛出多个异常,我们可以在throws后面写多个异常类使用,分开。也可使用Exception代替
public static void main(String[] args) throws FileNotFoundException,NullPointerException{
FileInputStream fis = new FileInputStream("d:/monkey1024.txt");
}
//使用Exception代替
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("d:/monkey1024.txt");
}
- 使用throws主要意图是暴露问题,如何解决让调用者去决定
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
// FileInputStream fis = new FileInputStream("file.txt");
// System.out.println("上面出现异常后,这里就不执行了");
m1();
System.out.println("main:出现异常后,不会打印该语句");
}
public static void m1() throws FileNotFoundException {
System.out.println("m1:出现异常后,不会打印该语句");
m2();
}
public static void m2() throws FileNotFoundException {
m3();
System.out.println("m2:出现异常后,不会打印该语句");
}
// 向上抛出异常
public static void m3() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("d:/monkey1024.txt");
}
//输出:m1:出现异常后,不会打印该语句
使用throw抛出异常对象
需要在方法体中抛出一个具体的异常对象时,可以使用throw关键字。
注意:在同一方法内,执行throw后会弹栈,它后面的代码就无法执行了。throw用于在方法内部出现某种情况程序不能继续运行时将异常抛出的场景。
import java.io.FileNotFoundException;
public class throwTest {
public static void main(String[] args) throws FileNotFoundException {
// TODO Auto-generated method stub
m1(-1);
}
public static void m1(int num) throws FileNotFoundException {
if(num<0) {
//期望抛出异常
//如果抛出运行时异常,则可以不用处理,编译可以通过
//throw new NullPointerException();
//Exception in thread "main" java.lang.NullPointerException
//如果抛出编译时异常,则必须处理,否则编译不通过
throw new FileNotFoundException();//通过方法将异常抛给调用者,通常不用try catch
}
System.out.println("throw后面的代码不会执行");//未执行
}
}
throw和throws的区别
throws
- 用在方法声明中,后面跟的是异常类
- 后面可以跟多个异常类名,用逗号隔开
- 表示抛出异常,由该方法的调用者来处理
throw
- 用在方法体内,后面跟的是异常对象
- 只能抛出一个异常对象
- 表示抛出异常,由方法体内的语句处理或抛出
try catch
使用try catch来处理异常,处理的意思是不会将异常抛出给调用者,而是自己来处理
当try语句块里面,某段代码出现异常之后,它后面的代码就不执行了,jvm会创建异常的对象,后面的catch会尝试对其进行捕获,如果catch中的异常类型跟当前异常相同或者是其父类时,此异常对象就会被捕获成功,然后赋值给后面的变量,在catch中的代码就会运行,通过变量就可以操作异常对象了。如果try中的代码没有出现异常或者catch捕获失败,此时catch中的代码不会执行
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
FileInputStream fip = new FileInputStream("tryfile.txt");
System.out.println("上面代码出现异常后,该语句就不执行了");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
/*
* 上面代码出现FileNotFoundException异常后会被catch捕获
* jvm会创建FileNotFoundException的对象,然后将e指向这个对象
*/
e.printStackTrace();// tryfile.txt (系统找不到指定的文件。)
System.out.println("出现异常,请联系管理员");
}
System.out.println("tryfile.txt");//catch后面的语句会正常执行
}
}
可以在catch中捕捉多个异常,但是catch里面必须从小类型异常到大类型异常进行捕捉,即先捕捉子后捕捉父,当某个catch捕获成功,其后面的catch不会再执行。
- 可以在catch中捕捉多个异常,但是catch里面必须从小类型异常到大类型异常进行捕捉,即先捕捉子后捕捉父,当某个catch捕获成功,其后面的catch不会再执行。
- 可以使用一个Exception捕获全部异常
- 一个catch捕获多个异常,使用|分割这些异常
catch (FileNotFoundException | ArithmeticException e) {
e.printStackTrace();
}
抛出和捕获
- throws:希望将异常信息向上反馈将其暴露出来时,需要使用throws抛出。
- try catch:需要自己对异常进行处理无需向上反馈时,使用try catch处理。
finally的使用
被finally修饰的语句一定会执行,除非在执行finally语句体之前JVM退出(比如System.exit(0))。finally通常用于释放资源的场景。
异常被捕获之后,会再执行finall中的内容
public class FinallyTest{
public static void main(String[] args) {
try {
System.out.println(1024 / 0);
} catch (ArithmeticException e) {
e.printStackTrace();
} finally{
System.out.println("finally中的内容");
}
}
}
即使在方法里面执行了return,finally中的代码也会执行
public static int m1(){
int i = 10;
try{
return i;
}finally{
System.out.println("finally中的语句");
}
}
只有当finally语句执行之前,JVM退出了,finally才不会执行:
int i = 10;
System.exit(0);//退出jvm
try{
return i;
}finally{
System.out.println("finally中的语句");
}
自定义异常
希望抛出一个非法注册名的异常,此时就需要自定义这个异常类了
public class Test {
public static void main(String[] args) throws IllegalNameException {
// TODO Auto-generated method stub
int n = 3;
if(n<6) {
throw new IllegalNameException("长度不足");
//Exception in thread "main" UserDefinedTest.IllegalNameException
}
}
}