Java异常(一)
1、Java异常
- 异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。
- Java中的异常用于处理非预期的情况,如文件没找到,网络错误,非法的参数
2、两类Java异常事件
Error: JVM系统内部错误、资源耗尽等严重情况
Exception: 其它因编程错误或偶然的外在因素导致的一般性问题。
例如:
-
空指针访问
-
试图读取不存在的文件
-
网络连接中断
3、几种异常分析举例
ArrayIndexOutOfBoundsException:数组下标越界异常
指数组下标超过初始化的范围。
代码示例如下:
String[] strs=new String[] { "a","b","c"};
for(int i = 0; i < strs.length+1; i++) {//i=0,1,2,3
//数组越界异常:java.lang.ArrayIndexOutOfBoundsException: 3
//这里的3就是异常下标
System.out.println(strs[i]);
//数组只有三个元素数组下标为0,1,2
//没有第四个元素,当输出strs[3]时没有
//所以当取到3时会出现数组下标越界
执行结果:
NullPointerException:空指针异常
引用指向的不是对象,是一个空指针
代码示例如下:
//正确的是A a=new A();
A a = null;//在这里指向,引用变量a没有指向任何对象,指向的是null
System.out.println(a.i);
//什么都没有指向i的值
//这里就会空指针异常
class A{
int i;
}
执行结果:
ArithmeticException:数学类异常
指不按数学规范计算,导致的错误结果的异常。
代码示例如下:
int i=0;
//除法分母不能等于0
System.out.println(3/i);
执行结果:
3、Java异常类层次
RuntimeException:运行时异常
-
错误的类型转换
-
数组下标越界
-
空指针访问
IOExeption:输入输出异常
-
从一个不存在的文件中读取数据
-
越过文件结尾继续读取EOFException
-
连接一个不存在的URL
4、异常处理
如果发生任何一种异常都会导致程序中断,影响后续就像下面的代码,不会执行输出Ok的道理。
示例代码:
int i=0;
System.out.println(3/i);
System.out.println("ok");
抓抛模型
Java提供的是异常处理的抓抛模型。
*** 注:抓抛模型说白了就是,抓(catch)是捕获的意思,抛(throws)是抛出的意思。***
Java程序的执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
如果一个方法内抛出异常,该异常会被抛到调用方法中。如果异常没有在调用方法中处理,它继续被抛给这个调用方法的调用者。
这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。
如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。
程序员通常只能处理Exception,而对Error无能为力。
捕获异常处理:
try catch用法:
? 一般catch经常和try搭配使用,用try{}来括住一段有可能出现异常的代码段
? catch括号内当不知道捕获的是什么类型的异常时,可以选择所有的异常的父类Exception先进行捕获。
代码如下:
int i=0;
try {
System.out.println(3/i);
} catch (Exception e) {
e.printStackTrace();//打印异常信息在程序中出错的位置及原因
System.out.println(e.getMessage());//打印异常原因
}
System.out.println("ok");
运行结果:
从结果来看,异常原因被抛出并且打印出来了,后续程序也可正常执行。
try catch finally用法:
在原来try catch的基础上多加一个finally{}程序块
int i=0;
try {
System.out.println(1);
System.out.println(3/i);
System.out.println(2);
} catch (Exception e) {
System.out.println(3);
}finally {
System.out.println(4);
}
System.out.println("ok");
}
运行结果:
从以上可以看到并没有输出2,是因为在输出语句之前出现了异常,捕捉到异常后,直接转到catch程序块执行输出3,跳过了输出2。
当catch有多个语句程序时,只优先执行第一句的异常,不会同时捕捉多个异常。
代码:
String[] strs= new String[] {"a","b"};
A a=null;
try {
System.out.println(strs[2]);
System.out.println(a.i);
} catch (ArrayIndexOutOfBoundsException e) {
// TODO: handle exception
System.out.println(e.getMessage());
//捕获数组异常
e.printStackTrace();
}
catch (NullPointerException e1) {
// TODO: handle exception
System.out.println(e1.getMessage());
//捕获空指针异常
e1.printStackTrace();
}
System.out.println("===================");
运行结果:
try catch没必要明确知道异常的具体类型,直接写
catch(Exception e){
//处理异常操作
e.printStackTrace();
//可以使用打印异常操作,打印异常原因
e.getMessage();
}
常常使用getMessage()方法和printStackTrace(),来用于捕获到的异常,进行打印异常事件的信息操作,打印跟踪执行堆栈的内容等操作。
声明抛出异常:
throws用法:
在使用throws方法之前,我们可以构想一个流程,加上之前学的捕获异常,我们可以先抛出异常在进行捕获
创建的对象调用方法的同时用throws进行抛出,再到主程序块进行捕获处理,
代码如下:
public class Test1 {
public static void main(String[] args) {//也可以在main方法抛出异常
//main方法抛出异常直接抛到虚拟机上去了,在程序中无法进行处理
B b = new B();
try {
b.test();
//throws在方法块抛出异常,
//在调用部分进行捕获处理
} catch (Exception e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
class B{
int i;
public void test() throws Exception{//可以使用throws在代码这抛出异常,在调用方捕获处理
B b=null;
System.out.println(b.i);
}
}
运行结果:
5、重写方法声明抛出异常的原则
当子类重写父类的方法时,子类不能抛出比父类方法更大范围的异常,这里如果子类C抛出Exception就会报错。
class B{
int i;
//NullPointerException的父类是RuntimeException
public void test() throws RuntimeException{//可以使用throws在代码这抛出异常,在调用方捕获处理
B b=null;
System.out.println(b.i);
}
}
class C extends B{
@Override
public void test() throws NullPointerException {
//重写方法不能抛出比被重写更大的异常类型
// TODO 自动生成的方法存根
super.test();
}
}
6、人工抛出异常
Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要人工创建并抛出
public class Test1 {
public static void main(String[] args) {
B b = new B();
try {
b.test1(-100);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
class B{
int i;
int age;
//NullPointerException的父类是Exception
public void test() throws NullPointerException{//可以使用throws在代码这抛出异常,在调用方捕获处理
B b=null;
System.out.println(b.i);
}
public void test1(int age) throws Exception{
if (age>=0 && age<=180) {
this.age=age;
System.out.println("年龄是:"+this.age);
}else {
throw new Exception("这个年龄不在0-150之间");
}
}
}
运行结果:
创建用户自定义异常类
java提供的异常的类一般是够用的,只有特殊情况可能需要自己编写异常类,并且这种情况及其少见。
public class Test1 {
public static void main(String[] args) throws MyException {//可以在main方法抛出异常
B b = new B();
try {
// b.test1(-100);
b.test2(-100);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
class B{
int i;
int age;
//NullPointerException的父类是Exception
public void test() throws NullPointerException{//可以使用throws在代码这抛出异常,在调用方捕获处理
B b=null;
System.out.println(b.i);
}
public void test1(int age) throws Exception{
if (age>=0 && age<=180) {
this.age=age;
System.out.println("年龄是:"+this.age);
}else {
throw new Exception("这个年龄不在0-150之间");
}
}
public void test2(int age) throws MyException {
if (age>=0 && age<=180) {
this.age=age;
System.out.println("年龄是:"+this.age);
}else {
throw new MyException("这个年龄不在0-150之间");
}
}
}
class MyException extends Exception{
public MyException(String msg) {
super(msg);
}
}
运行结果