文章目录
异常(Exception)
- Java 中的异常分为两大类:
a) Checked exception (非 Runtime Exception)
b) Unchecked exception(Runtime Exception) - Java 中所有的异常类都会直接或间接地继承自 Exception。
- RuntimeException 类也是直接继承自 Exception 类,它叫做运行时异常, Java 中所有
的运行时异常都会直接或间接地继承自 RuntimeException。 - Java 中凡是继承自 Exception 而不是继承自 RuntimeException 的类都是非运行时异
常。
异常处理的一般结构是:
try{ }
catch(Exception e){ }
finally{ }
无论程序是否出现异常, finally 块中的代码都是会被执行的。
只有try,catch可以,有try,finally也可以,但是光有catch,finally不可以,并且try中可以有多个catch,但是只有一个catch会执行
package Seventieth.Secound;
public class ExceptionTest {
public static void main(String[] args) {
int c = 0;
try{
int a = 3;
int b = 0;
c = a/b;
System.out.println("hello world");
}
catch(ArithmeticException e){
e.printStackTrace();
}
finally {//无论发不发生异常finally都会被执行
System.out.println("welcome");
}
System.out.println(c);
}
}
结果是:
java.lang.ArithmeticException: / by zero
at Seventieth.Secound.ExceptionTest.main(ExceptionTest.java:10)
welcome
0
- 对于非运行时异常(checked exception),必须要对其进行处理,处理方式有两种:
第一种是使用 try… catch…finally 进行捕获;第二种是在调用该会产生异常的方法所在
的方法声明 throws Exception
package Seventieth.Third;
public class ExcaptionTest2 {
public void method() throws Exception{//告诉其他方法我会抛出异常,真正生成异常是在方法里面
System.out.println("hello world");
throw new Exception();//生成异常对象,并抛出
}
public static void main(String[] args){
ExcaptionTest2 test = new ExcaptionTest2();
try{
test.method();
}
catch (Exception e){
e.printStackTrace();
}
finally {
System.out.println("aaa");
}
}
}
或者是
public static void main(String[] args) throws Exception{
ExcaptionTest2 test = new ExcaptionTest2();
test.method();//抛出Exception异常
}
结果是:
hello world
java.lang.Exception
at Seventieth.Third.ExcaptionTest2.method(ExcaptionTest2.java:8)
at Seventieth.Third.ExcaptionTest2.main(ExcaptionTest2.java:15)
aaa
如果main方法再往外抛出就抛给了Java虚拟机了。
- 对于运行时异常(runtime exception),我们可以不对其进行处理,也可以对其进行处理。推荐不对其进行处理。
- NullPointerException 是空指针异常, 出现该异常的原因在于某个引用为 null,但你却调用了它的某个方法。这时就会出现该异常。
package Seventieth.Third;
public class ExceptionTest3 {
public static void main(String[] args) {
String str = null;
System.out.println(str.length());
}
}
结果是:
Exception in thread “main” java.lang.NullPointerException
at Seventieth.Third.ExceptionTest3.main(ExceptionTest3.java:7)
自定义异常详解
- 所谓自定义异常, 通常就是定义了一个继承自 Exception 类的子类, 那么这个类就是一个自定义异常类。 通常情况下,我们都会直接继承自 Exception 类, 一般不会继承某个运行时的异常类。
package Seventieth.Fourth;
public class ExceptionTest4 {
public void method(String str) throws MyException{//这里可以抛出Exception,但是在catch中也要写Exception
if(str == null){
throw new MyException("传入的字符串参数不能为null");
}
else{
System.out.println(str);
}
}
/*public static void main(String[] args) throws MyException{
ExceptionTest4 test = new ExceptionTest4();
test.method(null);
System.out.println("此处不会被执行");
}
//如果选择这种方式,程序在异常处终止
执行结果
Exception in thread "main" Seventieth.Fourth.MyException: 传入的字符串参数不能为null
at Seventieth.Fourth.ExceptionTest4.method(ExceptionTest4.java:7)
at Seventieth.Fourth.ExceptionTest4.main(ExceptionTest4.java:18)
*/
public static void main(String[] args) {
try {
ExceptionTest4 test = new ExceptionTest4();
test.method(null);
} catch (MyException e) {//但是如果method抛出的是MyException也可以用Exception(多态)
e.printStackTrace();
}
finally {
System.out.println("异常处理完毕");
}
System.out.println("程序执行完毕");
}
//执行异常后继续往下执行
}
结果是:
Seventieth.Fourth.MyException: 传入的字符串参数不能为null
at Seventieth.Fourth.ExceptionTest4.method(ExceptionTest4.java:7)
at Seventieth.Fourth.ExceptionTest4.main(ExceptionTest4.java:25)
异常处理完毕
程序执行完毕
加入第二个异常
package Seventieth.Fifth;
public class MyException2 extends Exception{
public MyException2() {
super();
}
public MyException2(String message) {
super(message);
}
}
```ExceptionTest4
将ExceptionTest4改写如下
```java
package Seventieth.Fifth;
import Seventieth.Fourth.MyException;
public class ExceptionTest4 {
public void method(String str) throws MyException, MyException2{//这里可以抛出Exception,但是在catch中也要写Exception
if(str == null){
throw new MyException("传入的字符串参数不能为null");
}
else if("hello".equals(str)){
throw new MyException2("传入的字符串不能为hello");
}
else{
System.out.println(str);
}
}
public static void main(String[] args) {
try {
ExceptionTest4 test = new ExceptionTest4();
test.method("hello");
} catch (MyException e) {//但是如果method抛出的是MyException也可以用Exception(多态)
System.out.println("进入到MyException catch块");
e.printStackTrace();
}
catch (MyException2 e){
System.out.println("进入到MyException2 catch块");
e.printStackTrace();
}
finally {
System.out.println("异常处理完毕");
}
System.out.println("程序执行完毕");
}
//执行异常后继续往下执行
}
结果是:
进入到MyException2 catch块
Seventieth.Fifth.MyException2: 传入的字符串不能为hello
at Seventieth.Fifth.ExceptionTest4.method(ExceptionTest4.java:12)
at Seventieth.Fifth.ExceptionTest4.main(ExceptionTest4.java:25)
异常处理完毕
程序执行完毕
如果将method方法抛出的异常改为Exception(必须要是所有创建异常的父类,否则不可以这样写),那么在下列的try catch中必须加如一个Exception的catch(虽然他永远不会被执行),但是如果把MyException的catch删掉,也不会错,这样MyException的异常会进入Exception的catch块中进行,又但是,如果把Exception的catch块放在MyException块的上面那么MyException和MyException2两个的catch块永远不会被执行了所以==这种形式是不被允许的。==会报出Exception ‘Seventieth.Fourth.MyException’ has already been caught的错误
package Seventieth.Fifth;
import Seventieth.Fourth.MyException;
public class ExceptionTest4 {
public void method(String str) throws Exception{//这里可以抛出Exception,但是在catch中也要写Exception
if(str == null){
throw new MyException("传入的字符串参数不能为null");
}
else if("hello".equals(str)){
throw new MyException2("传入的字符串不能为hello");
}
else{
System.out.println(str);
}
}
public static void main(String[] args) {
try {
ExceptionTest4 test = new ExceptionTest4();
test.method("hello");
} catch (MyException e) {//但是如果method抛出的是MyException也可以用Exception(多态)
System.out.println("进入到MyException catch块");
e.printStackTrace();
}
catch (MyException2 e){
System.out.println("进入到MyException2 catch块");
e.printStackTrace();
}
catch (Exception e){
System.out.println("进入到Exception catch块");
e.printStackTrace();
}
finally {
System.out.println("异常处理完毕");
}
System.out.println("程序执行完毕");
}
//执行异常后继续往下执行
}
结果是:
进入到MyException2 catch块
Seventieth.Fifth.MyException2: 传入的字符串不能为hello
at Seventieth.Fifth.ExceptionTest4.method(ExceptionTest4.java:12)
at Seventieth.Fifth.ExceptionTest4.main(ExceptionTest4.java:25)
异常处理完毕
程序执行完毕
- 我们可以使用多个 catch 块来捕获异常,这时需要将父类型的 catch 块放到子类型的catch 块之后,这样才能保证后续的 catch 可能被执行,否则子类型的 catch 将永远无法到达,Java 编译器会报编译错误;如果多个 catch 块的异常类型是独立的(MyException, MyException2), 那么谁前谁后都是可以的。
- 如果 try 块中存在 return 语句,那么首先也需要将 finally 块中的代码执行完毕,然
后方法再返回。
package Seventieth.Fourth;
public class ExceptionTest5 {
public void method(){
try {
System.out.println("进入到try块");
return;
} catch (Exception e) {
System.out.println("异常发生了");
}
finally {
System.out.println("进入到finally块");
}
System.out.println("异常处理后续的代码");
}
public static void main(String[] args) {
ExceptionTest5 test = new ExceptionTest5();
test.method();
}
}
结果是:
进入到try块
进入到finally块
- 如果 try 块中存在 System.exit(0)语句,那么就不会执行 finally 块中的代码, 因为
System.exit(0)会终止当前运行的 Java 虚拟机,程序会在虚拟机终止前结束执行。
package Seventieth.Fourth;
public class ExceptionTest5 {
public void method(){
try {
System.out.println("进入到try块");
System.exit(0);
} catch (Exception e) {
System.out.println("异常发生了");
}
finally {
System.out.println("进入到finally块");
}
System.out.println("异常处理后续的代码");
}
public static void main(String[] args) {
ExceptionTest5 test = new ExceptionTest5();
test.method();
}
}
结果是:
进入到try块