文章目录
异常
一、异常
1. 异常的分类
java.lang.Throwable
是Java
语言中所有异常和错误的超类。Exception extends Throwable
:编译期异常,进行编译时Java
程序出现的问题。RuntimeException extends Exception
:运行期异常,Java
程序运行过程中出现的问题。
- 将异常处理掉,程序就可以继续执行。
Error extends Throwable
:错误,必须修改源代码,程序才能继续运行。
2. 异常的产生过程解析
3. 异常的处理
-
throw
关键字- 作用:可以使用
throw
关键字在指定的方法中抛出指定的异常。 - 使用格式:
throw new xxxException("异常产生的原因");
- 注意:
throw
关键字必须写在方法的内部。throw
关键字后边new
的对象必须是Exception
或者Exception
的子类对象。throw
关键字抛出指定的异常对象,我们就必须处理这个异常对象。throw
关键字后边创建的是RuntimeException
或者是RuntimeException
的子类对象,我们可以不处理,默认交给JVM
处理(打印异常对象,中断程序)。throw
关键字后边创建的是编译异常,我们就必须处理这个异常:throws
或者try...catch
。
public class Test { public static void main(String[] args) { int[] arr1 = null; //getElement(arr1,0); // NullPointerException: 传入的数组为null int[] arr2 = {1,2,3}; System.out.println(getElement(arr2, 0)); // 1 getElement(arr2,3); // ArrayIndexOutOfBoundsException: 传入索引错误 } private static int getElement(int[] arr, int index) { if (arr == null) { //运行时异常,默认交给JVM处理 throw new NullPointerException("传入的数组为null"); } else if (index < 0 || index > arr.length - 1) { //运行时异常,默认交给JVM处理 throw new ArrayIndexOutOfBoundsException("传入索引错误"); } return arr[index]; } }
- 作用:可以使用
4. Objets非空判断
-
Objects
类中的静态方法:-
public static <T> T requireNonNull(T obj)
:查看指定引用对象是否为null
。-
源码:
public static <T> T requireNonNull(T obj) { if (obj == null) { throw new NullPointerException(); } return obj; }
-
-
重载形式:
public static <T> T requireNonNull(T obj, String message)
-
import java.util.Objects;
public class Test {
public static void main(String[] args) {
//Objects.requireNonNull(null); // NullPointerException
Objects.requireNonNull(null,"空指针异常"); // NullPointerException: 空指针异常
}
}
5. throws关键字:异常处理的第一种方式,交给别人处理
-
作用:
- 当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象。
- 可以使用
throws
关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理,最终交给JVM
处理(中断处理)。
-
使用格式:在方法声明时使用。
修饰符 返回值类型 方法名(参数列表) throws AAAException,BBBException...{ throw new AAAException("产生原因"); throw new BBBException("产生原因"); ... }
-
注意:
throws
关键字必须写在方法声明处。throws
关键字后边声明的一场必须是Exception
或者是Exception
子类。- 方法内部如果抛出了多个异常对象,那么
throws
后边必须也声明多个异常。- 如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可。
- 调用了一个声明抛出异常的方法,我们就必须处理声明的异常。
- 要么继续使用
throws
声明抛出,交给方法的调用者处理,最终交给JVM
。 - 要么使用
try...catch
自己处理异常。
- 要么继续使用
public class Test {
public static void main(String[] args) throws IOException {
method("/Users/zgl/Desktop/a.txt"); // 读取文件
//method("/Users/zgl/Desktop/b.txt"); // FileNotFoundException: 没有该文件
method("a.tx"); // IOException: 文件后缀不是.txt
}
public static void method(String str) throws IOException {
/*if (!str.equals("/Users/zgl/Desktop/a.txt")) {
throw new FileNotFoundException("没有该文件");
} else*/ if (!str.endsWith(".txt")) {
throw new IOException("文件后缀不是.txt");
}
System.out.println("读取文件");
}
}
6. try…catch:处理异常的第二种方式,自己处理异常
-
格式:
try{ 可能产生异常的代码 }catch(定义一个异常的变量,用来接收try中抛出的异常对象){ 异常的处理逻辑,产生异常对象之后怎么处理这个异常 } ... catch(异常类名 变量名){ ... }
-
注意:
try
中可能会抛出多个异常对象,那么就可以使用多个catch
来处理这些异常对象。- 如果
try
中产生了异常,那么就会执行catch
中的异常处理逻辑,执行完毕catch
中的处理逻辑,继续执行try...catch
之后的代码。 - 如果
try
中没有产生异常,那么就不会执行catch
中的异常处理逻辑,执行完毕try
中的代码,继续执行try...catch
之后的代码。
import java.io.IOException; public class Test { public static void main(String[] args) { try{ method("a.txt"); // 读取文件 method("a.tx"); // catch: 后缀错误 }catch (IOException e) { System.out.println("catch: 后缀错误"); } System.out.println("catch后的后续代码"); // catch后的后续代码 } public static void method(String str) throws IOException { if (!str.endsWith(".txt")) { throw new IOException("后缀错误"); } System.out.println("读取文件"); } }
7. Throwable类中3个异常处理的方法
public String getMessage()
:返回此throwable
的简短描述。public String toString()
:返回此throwable
的详细消息字符串。public void printStackTrace()
:JVM
打印异常对象,默认采用此方法,打印的异常信息是最全面的。
import java.io.IOException;
public class Test {
public static void main(String[] args) {
try {
method("a.tx");
}catch (IOException e) {
System.out.println(e.getMessage()); // 后缀错误
System.out.println(e.toString()); // java.io.IOException: 后缀错误
System.out.println(e); // java.io.IOException: 后缀错误
/*
java.io.IOException: 后缀错误
at demo05.Test.method(Test.java:20)
at demo05.Test.main(Test.java:9)
*/
e.printStackTrace();
}
}
public static void method(String str) throws IOException {
if (!str.endsWith(".txt")) {
throw new IOException("后缀错误");
}
System.out.println("读取文件");
}
}
8. finally代码块
-
格式:
try{ 可能产生异常的代码 }catch(定义一个异常的变量,用来接收try中抛出的异常对象){ 异常的处理逻辑,产生异常对象之后怎么处理这个异常 } ... catch(异常类名 变量名){ ... }finally{ 无论是否出现异常,都会执行 }
-
注意:
finally
不能单独使用,必须和try
一起使用。finally
一般用于资源释放,无论程序是否出现异常,最后都要将资源释放。
import java.io.IOException; public class Test { public static void main(String[] args) { try { method("a.tx"); }catch (IOException e) { e.printStackTrace(); }finally { System.out.println("finally代码块"); } } public static void method(String str) throws IOException { if (!str.endsWith(".txt")) { throw new IOException("后缀错误"); } System.out.println("读取文件"); } }
9. 异常注意事项
-
多异常的捕获处理:
-
多个异常分别处理
import java.util.List; public class Test01 { public static void main(String[] args) { try { int[] arr = {1,2,3}; System.out.println(arr[3]); }catch (ArrayIndexOutOfBoundsException e) { System.out.println(e); // ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3 } try { List<Integer> list = List.of(1, 2, 3); System.out.println(list.get(3)); }catch (IndexOutOfBoundsException e) { System.out.println(e); // ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3 } } }
-
多个异常一次捕获,多次处理
- 注意:
catch
里边定义的异常变量,如果有子父类关系,那么子类的异常变量必须写在上边,否则就会报错。
import java.util.List; public class Test02 { public static void main(String[] args) { try { /*int[] arr = {1,2,3}; System.out.println(arr[3]);*/ List<Integer> list = List.of(1, 2, 3); System.out.println(list.get(3)); }catch (ArrayIndexOutOfBoundsException e) { System.out.println(e); // ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3 }catch (IndexOutOfBoundsException e) { System.out.println(e); // ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3 } } }
- 注意:
-
多个异常一次捕获一次处理
import java.util.List; public class Test03 { public static void main(String[] args) { try { int[] arr = {1,2,3}; System.out.println(arr[3]); List<Integer> list = List.of(1, 2, 3); System.out.println(list.get(3)); }catch (Exception e) { System.out.println(e); // ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3 } } }
-
-
finally
有return
语句- 如果
finally
中有return
语句,则永远返回的是finally
中的结果,需要避免该种情况。
- 如果
-
子父类异常
- 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
- 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常,此时子类产生异常,只能捕获处理,不能声明抛出。
10. 自定义异常类
-
java
提供的异常类,不够我们使用,需要自己定义一些异常类。 -
格式:
public class XXXException extends Exception/RuntimeException{ 添加一个空参数的构造方法 添加一个带异常信息的构造方法 }
-
注意:
- 自定义异常类一般都是以
Exception
结尾,说明该类是一个异常类。 - 自定义异常类,必须继承
Exception
或者RuntimeException
- 继承
Exception
:那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,使用throws
或者使用try...catch
。 - 继承
RuntimeException
:那么自定义的异常类就是一个运行期异常,无需处理,交给JVM
虚拟机处理(中断处理)。
- 继承
public class RegisterException extends Exception { public RegisterException(){ super(); } public RegisterException(String str){ super(str); } }
- 自定义异常类一般都是以