异常
什么是异常
相异与常态,和正常情况下不一致,有错误出现。 阻止当前方法或作用域的,称为异常。
异常分类
Throwable
类是Java异常类型的顶层父类,一个对象只有是 Throwable
类的(直接或者间接)实例,他才是一个异常对象,才能被异常处理机制识别。JDK中内建了一些常用的异常类,我们也可以自定义异常
Throwable
又派生出Error类
和Exception类
。
- Error
错误: Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。
- Exception
Exception以及他的子类,代表程序运行的发生的各种不同不期望的事件,可以被java的异常处理机制所捕获,是异常处理的核心。
总体上我们根据Javac对异常的处理要求,将异常类分为2类。
一、非检查异常
Error和RuntimeException,以及她们的子类。javac在比那一的时候,不会提示和发现这样的异常,不要求用程序去处理这些异常,所以,最好的解决办法就是,我们应该是修正代码,而不是捕获异常处理,这样的异常多半是代码写的有误。
如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。
二、检查异常
除了Error 和 RuntimeException的其它异常。javac强制要求对这类异常做预备处理(使用 try..catch..finally或者throws)。
在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。这样的异常一般是由程序的运行环境导致的。程序员就应该为这样的异常时刻准备着。
异常处理
try-catch
当遇到异常时,就会中断执行,然后程序的控制权将会移交catch中的异常处理程序
- try会抛出很多种类型的异常
针对不同的异常,在不同的catch中处理,但是我们仍然需要注意一下: (先写子类后写父类)
try-catch-finally
实例
package tryCatchDemo;
public class Testdemo {
public int test() {
int initNum = 10;
int result = 100;
try {
while(initNum > -1) {
initNum --;
result = result + 100/initNum;
}
return result;
}catch(Exception e) {
e.printStackTrace(); // 打印出错误
System.out.println("循环异常");
return -1;
}
}
}
package tryCatchDemo;
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Testdemo t = new Testdemo();
int result = t.test();
System.out.println("抛出异常了,此时返回值为"+ result);
}
}
- 修改一下
public int test1() {
int initNum = 10;
int result = 100;
try {
while(initNum > -1) {
initNum --;
result = result + 100/initNum;
}
return result;
}catch(Exception e) {
e.printStackTrace(); // 打印出错误
System.out.println("循环异常");
return -1;
}finally{
System.out.println("最终执行!!");
return 999;
}
}
- 再修改一下
public int test2() {
int initNum = 10;
int result = 100;
try {
while(initNum > -1) {
initNum --;
result = result + 100/initNum;
}
return result;
}catch(Exception e) {
e.printStackTrace(); // 打印出错误
System.out.println("循环异常");
return result = 1000;
}finally{
System.out.println("最终执行!!");
System.out.println("此时result的值为!!"+result);
}
}
异常的抛出
- throw 将产生的异常抛出(强调的是动作)
- throws 如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。
实例
package throw_demo1;
public class newError {
// 定义一个方法,抛出 数组越界和算术异常(多个异常 用 "," 隔开)
public void Test1(int x) throws ArrayIndexOutOfBoundsException,ArithmeticException{
System.out.println(x);
if(x == 0){
System.out.println("没有异常");
return;
}
//数据越界异常
else if (x == 1){
int[] a = new int[3];
a[3] = 5;
}
//算术异常
else if (x == 2){
int i = 0;
int j = 5/0;
}
}
}
package throw_demo1;
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建对象
newError object = new newError();
// 调用会抛出异常的方法,用try-catch块
try{
object.Test1(0);
}catch(Exception e){
System.out.println(e);
}
// 数组越界异常
try{
object.Test1(1);
}catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界异常:"+e);
}
// 算术异常
try{
object.Test1(2);
}catch(ArithmeticException e){
System.out.println("算术异常:"+e);
}
//使用 throw 抛出异常(可以抛出异常对象,也可以抛出异常对象的引用)
try{
ArrayIndexOutOfBoundsException exception = new ArrayIndexOutOfBoundsException();
// 抛出异常
throw exception;//new ArrayIndexOutOfBoundsException();
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("thorw抛出异常:"+e);
}
}
}
throw与throws的区别
1. throw 在方法体内使用,throws 函数名后或者参数列表后方法体前
2. throw 强调动作,而throws 表示一种倾向、可能但不一定实际发生
3. throws 后面跟的是异常类,可以一个,可以多个,多个用逗号隔开。throw 后跟的是异常对象,或者异常对象的引用。
自定义异常
class 自定义异常类 extends 异常类型(Exception){
// 因为父类已经把异常信息的操作都完成了,所在子类只要在构造时,将异常信息传递给父类通过super 语句即可。
// 重写 有参 和 无参 构造方法
}
// 一个DrunkException异常
package throwdemo2;
public class DrunkException extends Exception{
public DrunkException() {
super();
}
public DrunkException(String msg) {
super(msg);
}
}
异常链
实例
// DrunkException.java
package throwdemo2;
public class DrunkException extends Exception{
public DrunkException() {
super();
}
public DrunkException(String msg) {
super(msg);
}
}
//test.java
package throwdemo2;
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
test ct = new test();
try {
ct.test2();
}catch(Exception e) {
e.printStackTrace();
}
}
// 抛出一个异常
public void test1() throws DrunkException{
throw new DrunkException("你喝多了");
}
public void test2() {
try {
test1();
}catch(DrunkException e) {
// 捕获到test1的异常后,首先抛出一个运行时异常
RuntimeException newErr = new RuntimeException("喝酒误事");
// 设置该异常的造成原因为test1抛出的异常
newErr.initCause(e); //=> 这里是异常链的关键
// 抛出最后异常
throw newErr;
/**
* 同样异常链还可以是
* RuntimeException newErr = new RuntimeException(e);
* throw newErr;
*/
}
}
}
总结
1. 处理运行时异常时,采用逻辑去合理避免,同时配合try catch处理
2. 在多重catch之后,最好加上catch(Exception e)来处理可能会出现的异常
3. 对于不确定的代码,也可以加上try catch
4. 尽量去处理异常,切记只是简单的e.printStackTrace()去打印
5. 尽量添加finally语句去释放占用的资源
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。