一、异常处理
1.异常处理概述
1)使用返回值状态表示异常
在JAVA语言出现以前,传统的异常处理方式多采用返回值来标识程序出现的异常情况,这种方式虽然为程序员所熟悉,但却有多个坏处。
首先,一个API可以返回任意的返回值,而这些返回值本身并不能解释该返回值是否代表一个异常情况发生了和该异常的具体情况,需要调用API的程序自己判断并解释返回值的含义。
其次,并没有一种机制来保证异常情况一定会得到处理,调用程序可以简单的忽略该返回值,需要调用API的程序员记住去检测返回值并处理异常情况。这种方式还让程序代码变得冗长,尤其是当进行IO操作等容易出现异常情况的处理时,代码的很大部分用于处理异常情况的switch分支,程序代码的可读性变得很差。
2)异常处理机制
当程序中抛出一个异常后,程序从程序中导致异常的代码处跳出,java虚拟机检测寻找和try关键字匹配的处理该异常的catch块,如果找到,将控制权交到catch块中的代码,然后继续往下执行程序,try块中发生异常的代码不会被重新执行。如果没有找到处理该异常的catch块,在所有的finally块代码被执行和当前线程的所属的ThreadGroup的uncaughtException方法被调用后,遇到异常的当前线程被中止。
2.异常的捕获与处理
1)Throwable、Error和Exception
Java异常结构中定义有Throwable类,Exception和Error是其派生的两个子类。其中Exception表示由于网络故障、文件损坏、设备错误、用户输入非法等情况导致的异常;而Error表示Java运行时环境出现的错误,例如:JVM内存资源耗尽等。
2)try—catch
java 异常处理机制中的try-catch
语法:
try{
代码段
}catch(XXXException e){
try中出现XXXException后的处理代码
}
3)多个catch
public class TryCatchDemo {
public static void main(String[] args) {
System.out.println("程序开始了.....");
try {
// String str = null;
// String str = "";
String str = "a";
//当JVM执行程序时遇到异常,就会实例化这个异常的实例,并将执行过程设置其中然后抛出
System.out.println(str.length());
System.out.println(str.charAt(0));
System.out.println(Integer.parseInt(str));
//try语句块中出错代码以下的内容均不执行
System.out.println("!!!!!!!!!");
}catch(NullPointerException e){
System.out.println("出现空指针异常!!!");
}catch(StringIndexOutOfBoundsException e){
System.out.println("数组下标越界");
//可以在最后一个catch出捕获Exception,避免因为未处理异常导致程序中断
}catch(Exception e){
System.out.println("404");
}
System.out.println("程序结束了....");
}
}
4)finally的使用
异常处理机制中的finally
finally是异常处理机制中的最后一块,可以直接跟在try之后或者最后一个catch之后finally可以保证只要程序执行到try块中,无论是否抛出异常,finally都必执行,所以通常会将如释放资源等操作放在finally中确保执行
public class FinallyDemo {
public static void main(String[] args) {
System.out.println("程序开始了.....");
try {
// String line = null;
String line = "";
System.out.println(line.length());
return;
}catch(Exception e){
System.out.println("404");
}finally {
System.out.println("finally已经执行!");
}
// System.out.println("finally已经执行!");
System.out.println("程序结束了....");
}
}
public class FinallyDemo2 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("fos.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
try {
if (fos!=null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5)throw关键字
throw关键字用于主动对外抛出一个异常,通常下列情况会这样做:
1:程序遇到一个满足语法但不满足业务问题时,可以主动抛出异常给调用者告知不应当这样做
2:程序确实报错了,但是该错误不应该在当前代码片段中呗解决时可以对外抛出给调用者
public class ThrowDemo {
public static void main(String[] args) {
Person p = new Person();
try{
p.setAge(10000);//典型的满足语法,但是不满足业务需求
}catch(IllagalAgeException e){
e.printStackTrace();
}
System.out.println("今年"+p.getAge()+"岁");
}
}
6)throws关键字
当我们调用一个含有throws声明异常抛出方法时,编译器要求我们必须处理这个异常,处理方式:
1:自行try- catch
2:在当前方法上继续使用throws声明这个异常的抛出
具体使用那种要结合实际业务情况分析异常处理的责任问题
7)重写方法时的throws
import java.awt.*;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* 子类重写超类含有throws声明的方法时对其的重写规则
*/
public class ThrowsDemo {
public void dosome()throws IOException, AWTException{
}
}
class SubClass extends ThrowsDemo{
// public void dosome()throws IOException,AWTException{
// }
// 子类方法可以不在抛出任何异常
// public void dosome(){
// }
// 允许仅抛出部分异常
// public void dosome()throws IOException{
// }
// 可以抛出其超类方法抛出异常的子类型异常、
public void dosmoe()throws FileNotFoundException{
}
// 不允许抛出额外异常
// public void dosome()throws SQLException{
// }
// 不允许抛出超类方法抛出异常的超类型异常
// public void dosome()throws Exception{
// }
}
8)throw与throws的区别
throws:用来声明一个方法可能产生的所有异常,不做任何处理而是将异常往上传,谁调用我我就抛给谁。
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw:则是用来抛出一个具体的异常类型。
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
目录
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常
二、异常API
1.java异常API
1)RuntimeException
IllegalArgumentException:抛出的异常表明向方法传递了一个不合法或不正确的参数
NullPointerException:当应用程序试图在需要对象的地方使用null时,抛出该
异常
ArrayIndexOutOfBoundsException:当使用的数组下标超出数组允许范围时,抛出该异常
ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出该异常
NumberFormatException:当应用程序试图将字符串转换成一种数值类型,但该字符
串不能转换为适当格式时,抛出该异常。
2)常见的RuntimeException
NullPointerException | 空指针异常 | |
---|---|---|
ArrayIndexOutOfBoundsException | 数组下标越界异常 | |
ArithmeticException | 算术计算异常(如把零作为除数) | |
IllegalArgumentException | 方法接收到非法参数 | |
NumberFormatException | 数字格式转换异常(如把“123abc”转换成数字) | |
ClassCastexException | 两个类型不兼容时引发的运行时异常(例如:子类转换成父类) |
非检查异常(unckecked exception):Error 和 RuntimeException 以及他们的子类。除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等,
检查异常(checked exception):除了Error 和 RuntimeException的其它异常。如IOException,ClassNotFoundException 等。
2.Exception常用API
1)printStackTrace
Throwable中定义了一个方法可以输出错误信息,用来
跟踪异常事件发生时执行堆栈的内容。该方法定义为:
----void printStackTrace()
try{
}catch(Exception e){
e.printStackTrace();//输出执行堆栈信息
}
2)getMessage
Throwable中定义了一个方法可以得到有关异常事件的
信息。该方法定义为:
---- String getMessage(
try{
}catch(Exception e){
System.out.printIn(e.getMessageO);
}
3)getCause
很多时候,当一个异常由另一个异常导致异常而被抛出的时候,Java库和开放源代码会将一种异常包装成另一种异常。这时,日志记录和打印根异常就变得非常重要。Java异常类提供了getCause()方法来检索导致异常的原因,这些可以对异常根层次的原因提供更多的信息。该Java实践对代码的调试或故障排除有很大的帮助。另外,如果要把一个异常包装成另一种异常,构造一个新异常就要传递原异常。
Throwable getCause()
------获取该异常出现的原因
3.自定义Excepiton
1)自定义Excepiton的意义
Java异常机制可以保证程序更安全和更健壮。虽然Java
类库已经提供很多可以直接处理异常的类,但是有时候
为了更加精准地捕获和处理异常以呈现更好的用户体验,
需要开发者自定义异常。
2)继承Exception自定义异常
通常自定义异常是为了定义那些说明业务逻辑错误使用的。
自定义异常需要完成以下内容:
(1):定义类名
(2):继承自Exception(直接或间接继承都可以)
(3):提供者所有种类的构造器
public class IllagalAgeException extends Exception{
public IllagalAgeException() {
}
public IllagalAgeException(String message) {
super(message);
}
public IllagalAgeException(String message, Throwable cause) {
super(message, cause);
}
public IllagalAgeException(Throwable cause) {
super(cause);
}
public IllagalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}