茫茫人海千千万万,感谢这一秒你看到这里。希望我的文章对你的有所帮助!
愿你在未来的日子,保持热爱,奔赴山海!
相信各位都会在使用Java中或多或少的出现一些异常bug,那这些异常是从何而来的呢?
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。其实在Java中,异常是Java提供的一种识别及响应错误的一致性机制。从而可以达到程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并提高程序健壮性。
异常,就是不正常的意思。而在生活中:医生说,你的身体某个部位有异常,该部位和正常相比有点不同,该部位的功能将受影响。在程序中的意思就是:
所有的异常都是从Throwable继承而来的,是所有所有错误与异常的超类。Throwable包含了其线程创建时线程执行堆栈的快照,它提供了 printStackTrace()等接口用于获取堆栈跟踪数据等信息。
Exception 是另外一个非常重要的异常子类。程序本身可以捕获并且可以处理的异常。这类异常一旦出现,我们就要对代码进行更正,修复程序。Exception这种异常又分为两类:运行时异常和编译时异常。
通常,Java的异常(Throwable)分为受检异常(checked exceptions)和非受检异常(unchecked exceptions)。
编译器要求必须处理的异常。
编译器不会进行检查并且不要求必须处理的异常。
在 Java 应用程序中,异常处理机制为:抛出异常,捕捉异常。
这里先了解下关键词,具体定义格式和使用方法在下面介绍:
接下来用程序具体演示下吧:
public class ThrowDemo {
public static void main(String[] args) {
//创建一个数组
int[] arr = {2,4,52,2};
//根据索引找对应的元素
int index = 4;
int element = getElement(arr, index);
System.out.println(element);
System.out.println("over");
}
/*
* 根据 索引找到数组中对应的元素
*/
public static int getElement(int[] arr,int index){
//判断索引是否越界
if(index<0 || index>arr.length-1){
/*
判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。
*/
throw new ArrayIndexOutOfBoundsException("老弟,你的索引越界了,别这么干");
}
int element = arr[index];
return element;
}
}
运行后输出结果为:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 老弟,你的索引越界了,别这么干
at com.it.test2.ThrowDemo.getElement(ThrowDemo.java:25)
at com.it.test2.ThrowDemo.main(ThrowDemo.java:10)
可以看到我定义了索引为4,但是数组的长度只有4。所以会报错。
注意:所以如果产生了问题,我们就会throw将问题描述类即异常进行抛出,也就是将问题返回给该方法的调用者。结果是
ArrayIndexOutOfBoundsException 的数组索引越界的问题。
那么对于调用者来说,该怎么处理呢?一种是进行捕获处理,另一种就是继续讲问题声明出去,使用throws声明处理。
如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。例如汽车在运行时它可能会出现故障,汽车本身没办法处理这个故障,那就让开车的人来处理。
而throws用于进行异常类的声明,若该方法可能有多种异常情况产生,那么在throws后面可以写多个异常类,用逗号隔开。
public class ThrowsDemo2 {
public static void main(String[] args) throws IOException {
readFile("a.txt");
}
//若该方法可能有多种异常情况产生,那么在throws后面可以写多个异常类,用逗号隔开
//若有异常a是异常b的子类,也可以直接省略,写b异常
private static void readFile(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();
}
}
}
throws抛出异常的规则:
这三个关键字主要有下面几种组合方式try-catch 、try-finally、try-catch-finally。
注意:catch语句可以有一个或者多个或者没有,finally至多有一个,try必要有。
那这里你会问有没有单独try模块出现,那我想问下你,try是用来监听是否有异常,那如果发生了异常,谁来捕获呢?所以没有try单独出现。而且编译不能通过。
所以跟try模块一样,例如catch,finally也不能单独使用出现
捕获异常语法如下:
try{
编写可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
例如:
public class TryCatchDemo {
public static void main(String[] args) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
//当产生异常时,必须有处理方式。要么捕获,要么声明。
Date date = simpleDateFormat.parse("2020-10-06");
} catch (ParseException e) {// 括号中需要定义什么呢?
//try中抛出的是什么异常,在括号中就定义什么异常类型
e.printStackTrace();//记录日志/打印异常信息/继续抛出异常
}
/*
public Date parse(String source) throws ParseException{}
//parse抛出了ParseException异常
public class ParseException extends Exception {}
*/
}
}
如何获取异常信息:
Throwable类中定义了一些查看方法:
public class TryCathDemo2 {
public static void main(String[] args) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
//当产生异常时,必须有处理方式。要么捕获,要么声明。
//演示下获取异常信息,修改了格式。
Date date = simpleDateFormat.parse("2020年10月06");
} catch (ParseException e) {
//public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因
System.out.println(e.getMessage());//Unparseable date: "2020年10月06"
System.out.println(e.toString());//java.text.ParseException: Unparseable date: "2020年10月06"
e.printStackTrace();//输出信息而且飘红!!!
/*
java.text.ParseException: Unparseable date: "2020年10月06"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.it.test3.TryCathDemo2.main(TryCathDemo2.java:13)
*/
}
}
}
而如果有多个异常使用捕获我们又该如何处理呢?
一般我们是使用一次捕获多次处理方式,格式如下:
try{
编写可能会出现异常的代码
}catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
例如:
public class TryCatchDemo3 {
public static void main(String[] args) {
//test();
test2();
}
//多个异常一次捕获,多次处理。
public static void test2(){
int[] arr = {11, 22, 66, 0};
try {
//System.out.println(arr[5]);//一旦这个报错,下面的代码就不会执行
System.out.println(arr[2]);
System.out.println(arr[0] / arr[arr.length-1]);
} catch (ArithmeticException e) {
System.out.println("除数不为0");
}catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界");
}catch (Exception e) {
e.printStackTrace();
}
}
//分别处理的方式
public static void test() {
int a = 10;
int b = 0;
try {
System.out.println(a / b);
} catch (ArithmeticException e) {
System.out.println("除数不为0");//除数不为0
}
int[] arr = {1, 2, 3};
try {
System.out.println(arr[4]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界");//数组下标越界
}
}
}