Java(22)异常处理
异常处理
Java异常介绍
Java在程序执行过程中的不正常情况称为异常。捕获错误最理想时间是编译时候,但是有些错误在运行时才会报错。
Java程序运行过程中的异常主要分为两大类:
Error
:JVM系统内部错误、资源耗尽等情况。(程序员只能处理Exception,对Error无能为力。)Exception
:编程错误等一般问题,如空指针访问、读取不存在的文件。。。
- 异常案例1:数组越界异常
public class Test01{
public static int [] intarr={2,3,5};
public static void main(String[] args) {
for (int i = 0; i < 4; i++) { // i循环了0,1,2,3,但是数组长度只有3
System.out.println(intarr[i]);
}
}
}
/*
编译时不报错,运行报错:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
*/
- 异常案例2:空指针访问异常
class Tennis{
public int i=0;
}
public class Test01{
public static void main(String[] args) {
Tennis a=null; //a没有指向任何东西
System.out.println(a.i);
//编译时不会报错,运行时报错:
//Exception in thread "main" java.lang.NullPointerException
}
}
- 异常案例3:分母为0异常
public class Test01{
public static int i=0;
public static void main(String[] args) {
float a=3/i;
}
}
/*编译时不会报错,运行时报错:
Exception in thread "main" java.lang.ArithmeticException: / by zero
*/
Java异常类的层级
运行异常是运行才能发现的异常,是我们的常见异常,上面举的3个例子都是运行异常。
异常处理机制
Java异常处理:抓抛模型(捕获或者抛出)。
捕获异常:
Java通过try...catch...finally
捕获异常,语法格式如下:
try{
//可能产生异常的代码
}catch (ExceptionName1 e1){ //catch可以有多个
// 当产生ExceptionName1异常时执行措施
}catch (ExceptionName2 e2){
// 当产生ExceptionName2异常时执行措施
}finally { //finally部分可写可不写
//无条件执行语句,无论有没有异常都执行
}
案例1:
/**
* 通过try...catch来捕获处理:
* try{
*
* }catch(){
*
* }
*/
public class Test01{
public static int i=0;
public static void main(String[] args) {
//用try花括号括住可能出错的代码
try{
System.out.println(4/i);
}catch (Exception e){ //不知道捕获什么异常类时,可以使用异常的父类Exception
System.out.println(e.getMessage()); //这行代码可以查看捕获的异常是什么
e.printStackTrace(); //这行代码也可以查看捕获的异常是什么(打印方法调用栈)
//catch(){}花括号里面可以不写任何内容
}
System.out.println("Kobe,this is for you");//这行不受上面是否报异常的影响,
}
}
//运行结果为:Kobe,this is for you
案例2:
public class Test01{
public static void main(String[] args) {
String a=null;
try{
System.out.println(3/0);
System.out.println(a.toString());
}catch (java.lang.NullPointerException e1){
System.out.println("捕获到了java.lang.NullPointerException异常");
}catch (java.lang.ArithmeticException e2){
System.out.println("捕获到了java.lang.ArithmeticException异常");
}finally {
System.out.println("emm");
}
}
}
/*运行结果为:
捕获到了java.lang.ArithmeticException异常
emm
*/
/*
从运行输出结果可知,程序并没有把两个异常都捕获到了,只捕获到了3/0产生的ArithmeticException异常,
这是因为捕获异常本身的目的就是为了防止程序出现异常,如果try{}花括号里面前面的内容出现异常,就不会执行后面的内容了,所以没有捕获到a.toString()的空指针异常。
*/
抛出异常:
使用方式:throws+try...catch
案例1:
package day01;
public class Test01 {
public static void main(String[] args) {
Flower a=new Flower();
//调用fun1()时进行捕获异常:
try{
a.fun1();
}catch (Exception e){
e.printStackTrace();
}
}
}
class Flower{
void fun1() throws Exception{ //已经知道会报错,抛出异常
System.out.println(34/0);
}
}
如果有抛出,某个上层调用就要有捕获处理。抛出异常,是当前方法不处理异常,但是把异常往上层的调用栈传递,由上层选择捕获异常进行处理,还是选择继续往更上层抛出。如果main()方法抛出异常,异常交由虚拟机JVM处理。
案例2:
package day01;
class Flower{
static void fun1() throws Exception{ //异常从这里开始被抛出
System.out.println(34/0);
}
}
class Bee{
static void fun2() throws Exception{ //fun1()被调用,但是异常没有被捕获处理,继续抛出
Flower.fun1();
}
}
public class Test01 {
public static void main(String[] args) { //fun2()被调用,异常被捕获处理
try{
Bee.fun2();
}catch (Exception e){
e.printStackTrace();
}
}
}
/*运行结果为:
java.lang.ArithmeticException: / by zero
at day01.Flower.fun1(Test01.java:5)
at day01.Bee.fun2(Test01.java:10)
at day01.Test01.main(Test01.java:16)
*/
/*
Main调用fun2(),fun2()调用fun1()
printStackTrace()打印出了方法的调用栈,并给出了源代码的行号。
*/
案例3:如果异常被捕获并且继续抛出不同类型的异常(异常类型转换了),会发生什么?
package day01;
class Vege{
static void fun1(String s){
if(s==null){
throw new NullPointerException();
}else {
System.out.println(s);
}
}
}
class Ora{
static void fun2(){
try{
Vege.fun1(null);
}catch (NullPointerException e1){
throw new IllegalArgumentException();
}
}
}
class Test01{
public static void main(String[] args) {
try {
Ora.fun2();
}catch (IllegalArgumentException e2){
e2.printStackTrace();
}
}
}
/*运行结果为:
java.util.NoSuchElementException
at day01.Ora.fun2(Test01.java:22)
at day01.Test01.main(Test01.java:29)
*/
/*
从运行结果可以看到,看不到原始的空指针异常的信息了,如果想要查看完整异常栈,需要添加参数,将本源代码的
第18行的throw new IllegalArgumentException();
改成throw new IllegalArgumentException(e1);
*/
在Java中已经可以捕获异常了,为什么还要抛出异常再进行捕获,这种机制有什么作用?个人目前理解是,为了使已经知道可能出现异常的方法继续用下去,把抓到的异常抛出给调用者,让调用者来处理。
异常的屏蔽:
package day01;
class Police{
public static void main(String[] args) {
try{
System.out.println(4/0);
}catch (Exception e1){
throw new RuntimeException(e1);
}finally {
}
}
}
/*此处进行了异常转型,运行结果为:
Exception in thread "main" java.lang.IllegalArgumentException
at day01.Police.main(Test01.java:10)
*/
//----------------------如果finally也抛出异常:---------------
package day01;
class Police{
public static void main(String[] args) {
try{
System.out.println(4/0);
}catch (Exception e1){
throw new RuntimeException(e1);
}finally {
throw new IllegalArgumentException();
}
}
}
/*运行结果为:
Exception in thread "main" java.lang.IllegalArgumentException
at day01.Police.main(Test01.java:10)
*/
//从上面两段源代码运行结果可以知道,如果catch和finally同时准备抛出异常,catch的异常会被屏蔽不抛出