目录
异常处理:
异常处理概述:
使用返回值状态标识异常:
在JAVA语言出现以传统的异常处理方式多采用返回值来标识程序出现的异常情况,这种方式虽然为程序员所熟悉,但却有多个坏处。首先,一个API可以返回任意的返回值,而这些返回值本身并不能解释该返回值是否代表一一个异常情况发生了和该异常的具体情况,需要调用API的程序自己判断并解释返回值的含义。其次,并没有一种机制来保证异常情况一定会得到处理,调用程序可以简单的忽略该返回值,需要调用API的程序员记住去检测返回值并处理异常情况。这种方式还让程序代码变得冗长,尤其是当进行IO操作等容易出现异常情况的处理时,代码的很大部分用于处理异常情况的switch分支,程序代码的可读性变得很差。
异常处理机制:
当程序中抛出一个异常后, 程序从程序中导致异常的代码处跳出, java虚拟机检测寻找和try关键字匹配的处理该异常的catch块,如果找到,将控制权交到catch块中的代码,然后继续往下执行程序, try块中发生异常的代码不会被重新执行。如果没有找到处理该异常的catch块在所有的finally块代码被执行和当前线程的所属的ThreadGroup的uncaughtException方法被调用后,遇到异常的当前线程被中止。
异常的捕获和处理:
Throwable, Error和Exception
Java异常结构中定义有Throwable类, Exception和Error是其派生的两个子类。其中Exception表示由于网络故障、文件损坏、设备错误、用户输入非法等情况导致的异常;而Error表示Java运行时环境出现的错误,例如: JVM内存资源耗尽等。
Error:.是不能靠程序能处理的,比如:内存溢出。
Exception:运行时异常(非检查异常)和非运行时异常| (检查异常)
Exception | 名称 | 说明 |
常见的运行时异常: (非检测异常) | NullPointerException(空指针异常) | 当操作一个空引用抛出的一一个异常 |
NumberFormatException(数据格式化异常) | 试图将字符串转换为种数值类型时,但字符串转换不适当出现的异常 | |
ClassCastException (类型转换异常) | 强制类型转换不匹配时出现的异常。 | |
ArrayIndexOutOfBoundsExveption(数组下标越界异常) | :当使用-一个不存在的下标时出现的异常 | |
ArithmeticException(数字异常) | 异常运算条件时出现的 | |
非运行时异常: (可检测异常) | SQLException(操作数据库异常) | 访问数据库时出现的 |
lOException (IO异常) | 当发生某种I/O异常时抛出的 | |
ClassNotFoundException(类未找到异常) | 当应用程序使用Class类中的forName方法、loadClass方法时, 抛出的异常。 |
try- catch:
try {..} 语句指定了一段代码,该段代码就是一次捕获并处理例外的范围在执行过程中,该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句分别对这些异常做相应的处理如果没有异常产生,所有的catch代码段都被略过不执行在catch语句块中是对异常进行处理的代码在catch中声明的异常对像( catch(SomeException e) )封装了异常事件发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息。
每个try语句块可以伴随一一个或多个catch语句,用于处理可能产生的不同类型的异常catch捕获的异常类型由上至下的捕获异常类型的顺序应是子类到父类的。子类型异常在前,父类型异常在后,这样的顺序依次捕获。否则编译不通过。
public class TryCatchDemo {
public static void main(String[] args) {
System.out.println("程序开始了...");
try {
// String str = null;
// String str = "";
String str = "a";
System.out.println(str.length());
System.out.println(str.charAt(0));
System.out.println(Integer.parseInt(str));
//try语句块中出错代码以下的内容都不会执行
System.out.println("!!!!!!!!!!!!");
System.out.println("~~~~~~~~~~~~");
}catch(NullPointerException e) {
System.out.println("出现了空指针");
//catch可以定义多个,针对try中不同异常有不同处理时要分别捕获
}catch(StringIndexOutOfBoundsException e) {
System.out.println("出现了下标越界!");
//在最后一个catch处捕获Exception可防止未知异常导致程序中断
}catch(Exception e) {
System.out.println("反正就是出了个错!");
}
System.out.println("程序结束了!");
}
}
finally:
finally语句为异常处理提供个统的出口,使得在控制流程转到程序其它部分以前,能够对程序的状态作统管理。无论try所指定的程序块中是否抛出异常,finally所指定的代码都要被执行。
通常在finally语句中可以进行资源的释放工作,如关闭打开的文件、删除临时文件等。
在JDK7之后,java推出了一个特性:自动关闭。
该特性可以让我们应更精简的代码完成IO操作中的异常处理以及流的关闭。
补充:
final 是一个修饰词 .
finalize()是一个方法--在垃圾回收器GC,将对象从内存中清除之前做的必要的清理工作
package exception;
/**
* finally块
* finally块定义在异常处理机制的最后,可以直接跟在try块之后或者最后一个
* catch块之后。
* finally可以保证只要程序执行到try语句块中,无论try语句块中的代码是否
* 抛出异常,finally中的代码都必定执行。
*
*/
public class FinallyDemo1 {
public static void main(String[] args) {
System.out.println("程序开始了...");
try {
String str = "";
System.out.println(str.length());
/*
* 就算有return语句,也要先执行完finally中的代码后,方法才会
* 返回。
*/
return;
} catch (Exception e) {
System.out.println("出错了!");
} finally {
System.out.println("finally中的代码执行了!");
}
System.out.println("程序结束了!");
}
}
finally在IO中的应用:
public class FinallyDemo2 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("fos.dat");
fos.write(1);
System.out.println("写出完毕!");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(fos!=null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
自动关闭:
public class AutocloseableDemo {
public static void main(String[] args) {
/*
* try()中定义的流最终都会在finally中被关闭。该特性是编译器认可
* 的,代码最终会改为FinallyDemo2的样子。
* 并且需要注意,不是什么变量都可以定义在这里,只有实现了接口:
* AutoCloseable的才可以在这里定义。
* javaIO中的流和RandomAccessFile都实现了这个接口,可以定义在这里
*/
try(
FileOutputStream fos = new FileOutputStream("fos.dat");
//编译不通过,String没有实现AutoCloseable接口
// String str = "";
){
fos.write(1);
System.out.println("写出完毕!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
throw 关键字:
当程序发生错误而无法处理的时候,会抛出对应的异常对象,除此之外,在某些时刻您可能会想要自行抛出异常,例如在异常处理结束后, 再将异常抛出,让下一层异常处理块来捕捉, 若想要自行抛出异常,您可以使用"throw" 关键词,并生成指定的异常对象后抛出。
例如:
throw new ArithmeticException( );
throw关键字用于主动对外抛出一个异常
通常以下两种情况会主动抛出异常:
1:满足语法,但是不满足业务逻辑要求(当前案例就是这个情况)。
2:当前方法确实执行时出现了异常,但是当前方法不应该处理这个异常时,可以抛出给调用当前方法的代码片段去处理。
异常的抛出:
public class ThrowDemo {
public static void main(String[] args){
System.out.println("程序开始了...");
Person p = new Person();
/*
* 满足语法,但是不满足业务逻辑要求
*
* 当调用一个含有throws声明异常抛出的方法时,编译器要求我们必须定义
* 处理异常的手段,而处理异常有两种方式:
* 1:使用try-catch捕获其抛出的异常
* 2:在当前方法上继续使用throws声明该异常的抛出。
* 具体使用哪种视处理异常的责任而定,需要当前代码片段处理的就try-catch
* 否则就继续往外抛。但是永远不应当在main方法上声明throws。
*/
try {
p.setAge(10000);
} catch (IllegalAgeException e) {
e.printStackTrace();
}
System.out.println("今年:"+p.getAge()+"岁");
System.out.println("程序结束了...");
}
}
public class Person {
private int age;
public int getAge() {
return age;
}
/**
* throw关键字用于主动对外抛出一个异常
* 通常以下两种情况会主动抛出异常:
* 1:满足语法,但是不满足业务逻辑要求(当前案例就是这个情况)。
* 2:当前方法确实执行时出现了异常,但是当前方法不应该处理这个异常时,
* 可以抛出给调用当前方法的代码片段去处理。
* @param age
* @throws Exception
*/
public void setAge(int age) throws IllegalAgeException {
if(age<0||age>100) {
/*
* 当我们使用throw抛出一个异常时(除了RuntimeException及其子类型
* 异常)编译器要求我们必须处理该异常。而这里处理异常的方式就是在
* 当前方法上使用throws声明该异常的抛出
*/
throw new IllegalAgeException("年龄不合法!");
}
this.age = age;
}
}
throws 关键字:
程序中会声明许多方法( Method ) , 这些方法中可能会因某些错误而引发异常,但您不希望直接在这个方法中处理这些异常,而希望调用这个它的方法来统一处理,这时候您可以使用"throws" 关键词来声明这个方法将会抛出异常。
重写方法时的throws:
如果使用继承时,在父类别的某个方法上宣告了throws某些异常,而在子类别中重新定义该方法时,可以:
- 不处理异常(重新定义时不设定throws )
- throws父类别中声明的部分异常
- throws父类方法中抛出异常的子类异常
但是不可以:
- throws出额外的异常
- 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 dosome() throws FileNotFoundException{
//
// }
//不允许抛出额外的异常(父类方法没有抛出的异常,也不是子类型异常)
// public void dosome() throws SQLException{
//
// }
//不允许抛出父类方法抛出异常的父类型异常
// public void dosome() throws Exception{
//
// }
}
异常API:
Java异常API:
RuntimeException:
Java异常可以分为可检测异常,非检测异常:
可检测异常:可检测异常经编译器验证,对于声明抛出异常的任何方法,编译器将强制执行处理或声明规则,不捕捉这个异常,编译器就通不过,不允许编译。
非检测异常:非检测异常不遵循处理或者声明规则。在产生此类异常时,不一定非要采取任何适当操作,编译器不会检查是否已经解决了这样一个异常。
RuntimeException类属于非检测异常,因为普通JVM操作引|起的运行时异常随时可能发生,此类异常一般是由特定操作弓|发。但这些操作在java应用程序中会频繁出现。因此它们不受编译器检查与处理或声明规则的限制。
常见的RuntimeException:
IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数 |
NullPointerException | 当应用程序试图在需要对象的地方使用null时,抛出该 |
ArrayIndexOutOfBoundsException | 当使用的数组下标超出数组允许范围时,抛出该异常 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符 |
测试常见的运行时异常
测试空指针异常
测试数组下标越界异常
测试数学异常
测试强制类型转换异常
测试NumberF ormat异常
Exception常用API:
printStackTrace:
Throwable中定义了一个方法可以输出错误信息,用来跟踪异常事件发生时执行堆栈的内容。该方法定义为:
void printStackTrace( )
getMessage:
Throwable中定义了一个方法可以得到有关异常事件的信息。该方法定,义为:
String getMessage( )
public class ExceptionAPIDemo {
public static void main(String[] args) {
System.out.println("程序开始了");
try {
String str = "";
/*
* 当我们将一个字符串解析为基本类型时,如果字符串内容不能正确
* 表示基本类型值时,就会抛出NumberFormatException
*/
System.out.println(Integer.parseInt(str));
} catch (Exception e) {
System.out.println("出错了!");
//输出错误堆栈信息,便于debug
e.printStackTrace();
//获取错误消息
String message = e.getMessage();
System.out.println(message);
}
System.out.println("程序结束了");
}
}
getCause:
很多时候,当一个异常由另一个异常导致异常而被抛出的时候,Java库和开放源代码会将一种异常包装成另一 种异常。这时,日志记录和J印根异常就变得非常重要。Java异常类提供了getCause(方法来检索导致异常的原因,这些可以对异常根层次的原因提供更多的信息。该Java实践对代码的调试或故障排除有很大的帮助。另外,如果要把一个异常包装成另一种异常,构造一个新异常就要传递原异常。
Throwable getCause( )——获取该异常出现的原因
自定义Exception:
自定义Exception的意义:
Java异常机制可以保证程序更安全和更健壮。虽然Java类库已经提供很多可以直接处理异常的类,但是有时候为了更加精准地捕获和处理异常以呈现更好的用户体验需要开发者自定义异常。
继承Exception自定义异常
继承Exception自定义异常,创建自定,义异常类,语法格式:
class [自定义异常类名] extends Exception{
}
如何编写构造方法
当定义好自定义异常后,我们可以通过Eclipse来自动生成相应的构造方法。
package exception;
/**
* 自定义异常
* 通常自定义异常用在符合语法但是不符合业务逻辑问题时的异常。
*
* 自定义异常最重要的就是名字,要做到见名知意
* 自定义异常实现步骤:
* 1:定义类名
* 2:继承Exception(直接或间接继承)
* 3:提供所有构造方法
* 4:定义序列化版本号(避免代码出现警告)
*
*/
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
}
}