Exception:编译期异常,进行编译(写代码)java程序出现的问题
RuntimeException:运行期异常,java程序运行过程中出现的问题
异常就相当于程序得了一个小毛病(感冒,发烧),把异常处理掉,程序可以继续执行(吃点药,继续革命工作)
Error:错误
错误就相当于程序得了一个无法治愈的毛病(非典,艾滋).必须修改源代码,程序才能继续执行
throw关键字
作用:
可以使用throw关键字在指定的方法中抛出指定的异常
使用格式:
throw new xxxException("异常产生的原因");
注意:
1.throw关键字必须写在方法的内部
2.throw关键字后边new的对象必须是Exception或者Exception的子类对象
3.throw关键字抛出指定的异常对象,我们就必须处理这个异常对象
throw关键字后边创建的是RuntimeException或者是 RuntimeException的子类对象,我们可以不处理,默认交给JVM处理(打印异常对象,中断程序)
throw关键字后边创建的是编译异常(写代码的时候报错),我们就必须处理这个异常,要么throws,要么try...catch
package com.itheima.demo01.Exception;
public class Demo03Throw {
public static void main(String[] args)
{
//int[] arr = null;
int[] arr = new int[3];
int e = getElement(arr,3);
System.out.println(e);
}
public static int getElement(int[] arr,int index){
/*
我们可以对传递过来的参数数组,进行合法性校验
如果数组arr的值是null
那么我们就抛出空指针异常,告知方法的调用者"传递的数组的值是null"
*/
if(arr == null){
throw new NullPointerException("传递的数组的值是null"); //为空则报异常, 抛指定异常
}
/*
我们可以对传递过来的参数index进行合法性校验
如果index的范围不在数组的索引范围内
那么我们就抛出数组索引越界异常,告知方法的调用者"传递的索引超出了数组的使用范围"
*/
if(index<0 || index>arr.length-1){
throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的使用范围"); // 越界异常
}
int ele = arr[index];
return ele;
}
}
定义一个方法,获取数组指定索引处的元素
参数:
int[] arr
int index
以后(工作中)我们首先必须对方法传递过来的参数进行合法性校验
如果参数不合法,那么我们就必须使用抛出异常的方式,告知方法的调用者,传递的参数有问题
注意:
NullPointerException是一个运行期异常,我们不用处理,默认交给JVM处理
ArrayIndexOutOfBoundsException是一个运行期异常,我们不用处理,默认交给JVM处理
抛出指定异常,异常内容自己填写。
如果getElement(arr,3),则报越界ArrayIndexOutOfBoundsException异常,如果getElement(null, 2),则报NullPointerException错误。
Objects非空判断
还记得我们学习过一个类Objects吗,曾经提到过它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),那么在它的源码中,对对象为null的值进行了抛出异常操作。
-
public static <T> T requireNonNull(T obj)
:查看指定引用对象不是null。
package com.itheima.demo01.Exception;
import java.util.Objects;
/*
Obects类中的静态方法
public static <T> T requireNonNull(T obj):查看指定引用对象不是null。
源码:
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
*/
public class Demo04Objects {
public static void main(String[] args) {
method(null); // 空指针
}
public static void method(Object obj){
//对传递过来的参数进行合法性判断,判断是否为null
// if(obj == null){
// throw new NullPointerException("传递的对象的值是null");
// }
//Objects.requireNonNull(obj);
Objects.requireNonNull(obj,"传递的对象的值是null"); // 可以判断传入对象是否为空
}
}
Objects.requireNonNull(obj,"传递的对象的值是null"); 可以更简单的判断传入对象是否为空,不需要自己写判断。
执行结果:
Exception in thread "main" java.lang.NullPointerException: 传递的对象的值是null
at java.base/java.util.Objects.requireNonNull(Objects.java:246)
at com.itheima.demo01.Exception.Demo04Objects.method(Demo04Objects.java:27)
at com.itheima.demo01.Exception.Demo04Objects.main(Demo04Objects.java:17)
Process finished with exit code 1
声明异常throws
声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲解该方式),那么必须通过throws进行声明,让调用者去处理。
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
声明异常格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }
声明异常的代码演示:
public class ThrowsDemo {
public static void main(String[] args) throws FileNotFoundException {
read("a.txt");
}
// 如果定义功能时有问题发生需要报告给调用者。可以通过在方法上使用throws关键字进行声明
public static void read(String path) throws FileNotFoundException {
if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
// 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw
throw new FileNotFoundException("文件不存在");
}
}
}
throws用于进行异常类的声明,若该方法可能有多种异常情况产生,那么在throws后面可以写多个异常类,用逗号隔开。
public class ThrowsDemo2 {
public static void main(String[] args) throws IOException {
read("a.txt");
}
public static void read(String path)throws FileNotFoundException, IOException {
if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
// 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw
throw new FileNotFoundException("文件不存在");
}
if (!path.equals("b.txt")) {
throw new IOException();
}
}
}
捕获异常try…catch
如果异常出现的话,会立刻终止程序,所以我们得处理异常:
-
该方法不处理,而是声明抛出,由该方法的调用者来处理(throws)。
-
在方法中使用try-catch的语句块来处理异常。
try-catch的方式就是捕获异常。
-
捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。
捕获异常语法如下:
try{
编写可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
try:该代码块中编写可能产生异常的代码。
catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理。
注意:try和catch都不能单独使用,必须连用。
注意:
1.try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象
2.如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try...catch之后的代码
如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try...catch之后的代码
package com.itheima.demo02.Exception;
import java.io.IOException;
public class Demo01TryCatch {
public static void main(String[] args) {
try{
//可能产生异常的代码
readFile("d:\\a.tx");
System.out.println("资源释放");
}catch (IOException e){//try中抛出什么异常对象,catch就定义什么异常变量,用来接收这个异常对象
//异常的处理逻辑,异常异常对象之后,怎么处理异常对象
//System.out.println("catch - 传递的文件后缀不是.txt");
/*
Throwable类中定义了3个异常处理的方法
String getMessage() 返回此 throwable 的简短描述。
String toString() 返回此 throwable 的详细消息字符串。
void printStackTrace() JVM打印异常对象,默认此方法,打印的异常信息是最全面的
*/
// System.out.println(e.getMessage());//文件的后缀名不对
// System.out.println(e.toString());//重写Object类的toString java.io.IOException: 文件的后缀名不对
// System.out.println(e);//java.io.IOException: 文件的后缀名不对
// e.printStackTrace();
}
System.out.println("后续代码");
}
/*
如果传递的路径,不是.txt结尾
那么我们就抛出IO异常对象,告知方法的调用者,文件的后缀名不对
*/
public static void readFile(String fileName) throws IOException {
if(!fileName.endsWith(".txt")){
throw new IOException("文件的后缀名不对"); //判断文件名是不是对的
}
System.out.println("路径没有问题,读取文件");
}
}
如何获取异常信息:
Throwable类中定义了一些查看方法:
-
public String getMessage()
:获取异常的描述信息,原因(提示给用户的时候,就提示错误原因。
-
public String toString()
:获取异常的类型和异常描述信息(不用)。 -
public void printStackTrace()
:打印异常的跟踪栈信息并输出到控制台。
包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。