异常处理
当程序中抛出一个异常后,程序从程序中导致异常的代码处跳出,java虚拟机检测寻找和try关键字匹配的处理该异常的catch块,如果找到,将控制权交到catch块中的代码,然后继续往下执行程序,try块中发生异常的代码不会被重新执行。如果没有找到处理该异常的catch块,在所有的finally块代码被执行和当前线程的所属的 ThreadGroup 的 uncaughtException 方法被调用后,遇到异常的当前线程被中止。
Throwable,Error和Exception
Java异常结构中定义有Throwable类,Exceotion和Error是其派生的两个子类。其中Exception表示由于网络故障、文件损坏、设备错误、用户输入非法等情况导致的异常,这类异常是可以通过Java异常捕获机制处理的。而Error表示Java运行时环境出现的错误,例如:JVM内存溢出等。
try-catch
java异常处理机制中的try——catch
try 块用来包含可能出错的代码片段
catch用来捕获try块中出现的错误并解决
/*
*java异常捕获机制中的try-catch
*结构:
*try{
* 可能出现错误的代码片段
* }catch(要捕获的异常类型){
* 处理手段
* }
* @author jiyiyuan
*
*/
public class Exception_try_catch01 {
public static void main(String[] args) {
System.out.println("程序开始了");
try {
String str="a";
System.out.println(str.length());
System.out.println(str.charAt(0));
//System.out.println(Integer.parseInt(str));
/**
* try块中出错的代码以下的内容都不会再执行。
*/
System.out.println("!!!!!!!!!!");
}catch(NullPointerException n) {
System.out.println("空指针异常");
}catch(StringIndexOutOfBoundsException n){
System.out.println("字符串下标越界");
/**
* catch可以定义多个,针对不同异常有不同解决手段应对针对这些异常进行捕获。但是应当养成一个好的习惯,在最后捕获Exception,
* 这样做可以避免因为try代码块中抛出一个未捕获异常导致程序中断。当捕获的异常存在继承关系时,应当将子类型异常定义在上面先行捕获。
*/
}catch(Exception e){
System.out.println("反对就是出了个错");
}finally {
System.out.println("程序结束了");
}
}
}
运行结果:
finally的作用
finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序其它部分以前,能够对程序的状态作统一管理。
无论try所指定的程序块中是否抛出例外,finally所指定的代码都要被执行,通常在finally语句中可以进行资源的消除工作,如关闭打开的文件、删除临时文件等。
finally 语句块只能定义在try语句块之后,或者最后一个catch语句块之后,且只能定义一次。
finally 块必须定义在异常处理机制的最后
finally块可以保证无论try块中的代码是否出现异常,finally块中的代码都会执行 通常会将诸如释放资源操作放在finally中确保执行
/*
* finally块
* finally只能定义在异常捕获机制的最后可以直接跟在try块之后或者最后一个catch之后
*
* finally可以保证里面的代码一定执行。所以通常会将无乎异常而不需要运行的代码定义在finally确保它们可以被运行。比如流操作中关闭流就应当放在finally中。
*/
public class Exception_finally02 {
public static void main(String[] args) {
System.out.println("程序开始了。");
try {
String str="";
System.out.println(str.length());
return;
}catch(Exception e){
System.out.println("出错了。");
}finally{
System.out.println("finally中的代码执行");
}
System.out.println("程序结束了。");
}
}
运行结果:
通常两种情况导致异常抛出
1.满足语法要求,但是不满足业务逻辑要求时,可以当作一个异常抛出给调用者。
2.当前代码出现了异常,但是该异常的解决不应再当前代码中处理时可以将其抛出给调用者解决。
throw关键字
当程序发生错误而无法处理的时候,会抛出对应的异常对象,除此之外,在某些时刻,您可能会想要自行抛出异常,例如在异常处理结束后,再将异常抛出,让下一层异常处理区块来捕捉,若想要自行抛出异常,您可以使用“throw”关键词,并生成指定的异常对象。程序中会声明许多方法(Method),这些方法中可能会因某些错误而引发异常,但您不希望直接在这个方法中处理这些异常,而希望调用这个它的方法来统一处理,这时候您可以使用“throws”关键词来声明这个方法将会抛出异常
/**
* 测试异常抛出相关操作
* @author jiyiyuan
*
*/
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age)throws IllegalAgeException {
if(age<0||age>100) {
/**
* throw用于主动抛出一个异常除了RuntimeException及其子类型异常外,抛出什么异常就必须在当前方法上使用
* throws声明该类型异常的抛出定义以通知调用者处理该异常。
*/
throw new IllegalAgeException("年龄不合法!");
}
this.age = age;
}
}
public class Exception_throw04 {
public static void main(String[] args) {
System.out.println("开始了");
try {
Person p=new Person();
/**
* 当调用一个含有throws声明异常抛出的方法时,编译器要求必须处理这 些异常。
* 处理方式有两种:
* 1.使用try-catch捕获并处理;
* 2.继续在当前方法上使用throws将该类异常声明抛出;
*/
p.setAge(1000);
System.out.println(p.getAge());
} catch (IllegalAgeException e) {
e.printStackTrace();
}
System.out.println("程序结束啦");
}
}
运行结果:
重写方法时的throws
当使用继承时,在父类的某个方法上声明了throws抛出某些异常,而在子类中重写该方法时,我们可以做以下的操作:
- 不处理异常(重写方法时不声明throws)
- 可仅在throws中声明父类中声明的部分异常
- 可在throws中声明父类方法中抛出的异常的子类异常
但是不能做以下操作:
- 重写方法时在throws中声明抛出额外的异常
重写方法时在throws中声明父类方法中声明的抛出异常的父类异常
/**
* 子类在重写父类一个含有throws声明异常抛出的方法 时对throws的重写规则。
* @author jiyiyuan
*
*/
public class Exception_throws_override05 {
public void dosome()throws IOException,AWTException{
}
}
class Son extends Exception_throws_override05{
/*
* public void dosome()throws IOException,AWTException {
*
* }
*/
//仅抛出部分异常
/*
* public void dosome()throws IOException {
*
* }
*/
//不再抛出任何异常
/*
* public void dosome() {
*
* }
*/
//抛出父类方法抛出的异常的子类型异常
/*
* public void dosome()throws FileNotFoundException {
*
* }
*/
//不允许抛出额外异常
/*
* public void dosome()throws SQLException {
*
* }
*/
//不允许抛出父类方法抛出异常的父类型异常
/*
* public void dosome() throws Exception{
*
* }
*/
}
Java异常API
/**
* 异常常用方法
* @author jiyiyuan
*
*/
public class Exception_API06 {
public static void main(String[] args) {
System.out.println("程序开始了");
try {
String str="a";
System.out.println(Integer.parseInt(str));
}catch(Exception e) {
//输出错误堆栈信息,有助于定位错误并调整。
e.printStackTrace();
String message=e.getMessage();
System.out.println("message:"+message);
}
System.out.println("程序结束了");
}
}
运行结果:
getCause
很多时候,当一个异常由另一个异常导致异常而被抛出的时候,Java库和开放源代码会将一种异常包装成另一种异常。这时,日志记录和打印根异常就变得非常重要。Java异常类提供了 getCause()方法来检索导致异常的原因,这些可以对异常根层次的原因提供更多的信息。该Java实践对代码的调试或故障排除有很大的帮助。另外,如果要把一个异常包装成另一种异常,构造一个新异常就要传递源异常。
自定义Exception
Java异常机制可以保证程序更安全和更健壮。虽然Java类库已经提供很多可以直接处理异常的类,但是有时候为了更加精准地捕获和处理异常以呈现更好的用户体验,需要开发者自定义异常。
如何编写构造方法
当定义好自定义异常后,我们可以通过Eclipse来自动生成相应的构造方法。
具体步骤如下:
- 声明一个类并继承自Exception
- 右键点击Source
- 选择Generate Constructors from Superclass
- 选中父类中所有构造方法后确认生成
/**
* 年龄不合法异常
*
* 自定义异常通常用来说明我们写的项目中的某个业务逻辑
* 错误。
* @author jiyiyuan
*
*/
public class IllegalAgeException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public IllegalAgeException() {
super();
// TODO Auto-generated constructor stub
}
public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public IllegalAgeException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public IllegalAgeException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public IllegalAgeException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}
Error 类和 Exception 类的父类都是 Throwable 类,他们的区别如下。
1. Error 类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢出等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
2. Exception 类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
3. Exception 类又分为运行时异常(Runtime Exception)和受检查的异常(Checked Exception ),运行时异常;ArithmaticException,IllegalArgumentException,编译能通过,但是一运行就终止了,程序不会处理运行时异常,
出现这类异常,程序会终止。而受检查的异常,要么用 try。。。catch 捕获,要么用 throws 字句声明抛出,交给它的父类处理,否则编译不会通过。
2019-12-22 22:25:58