JavaSE之异常与捕获

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HL_HLHL/article/details/84001058


几乎所有的代码里面都会出现异常,为了保证程序在出现异常之后可以正常执行完毕,就需要进行异常处理。
先看一下异常的继承类结果:
在这里插入图片描述
所有的异常都是由 Throwable继承而来,我们来看他下面的两个子类Error和Exception。
Error类(栈溢出异常)描述了java运行时内部错误和资源耗尽错误。应用程序不抛出此类异常,这种内部错误一旦出现,除了告知用户并使程序安全终止之外,在无能为力。这种情况很少见。
RuntimeException(运行时异常):由于程序错误导致的异常。
IOException:程序本身没有问题,但由于出现I/O问题导致的异常(例如:打开一个并不存在的文件)
非受查异常:继承于Error与RuntimeException类的所有异常子类称为非受查异常(不强制用户进行异常处理)
受查异常:Exception以及IOException子类属于受查异常(强制用户进行异常处理)

异常的影响

异常是导致程序中断执行的一种指令流。程序之中如果出现异常并且没有合理处理的话就会导致程序终止执行。
范例:程序产生异常

public class Test {
    public static void main(String[] args) {
        System.out.println("1.数学计算开始前..");
        System.out.println("2.数学计算开始中"+(10/0));
        System.out.println("3.数学计算完成..");
    }
}

运行结果:
在这里插入图片描述
现在程序中产生了异常,但是在异常语句产生之前的语句可以正常执行完毕,而异常产生之后程序直接结束。

异常处理格式

为了保证程序出现异常后也能正常执行下去,需要进行异常处理。
异常处理的语法格式如下:

try{
    // 有可能出现异常的语句;
     }[catch (异常类 对象)....]{
     //出现异常后的解决方法
     }
     [finally]{
     //异常的出口,无论是否产生异常,均会执行finally代码块
     //即使try、catch中存在return语句,也会在return之前执行finally语句
     }

异常的三种模式组合:
try…catch…
try…finally…
try…catch…finallly…
范例:对异常的处理和打印

public class Test {
    public static void main(String[] args) {
        System.out.println("1.数学计算开始前..");
        //异常处理
        try {
        //可能出现异常的语句
            System.out.println("2.数学计算开始中"+(10/0));
        } catch (RuntimeException e) {
        //打印异常信息
           e.printStackTrace();
        }
        System.out.println("3.数学计算完成..");
    }
}

在这里插入图片描述
出现异常之后,由于存在异常处理机制,依然可以正常执行完毕。
范例:使用try…catch…finally进行处理

public class Test {
    public static void main(String[] args) {
        System.out.println("1.数学计算开始前..");
        try {
            //肯出现异常的语句
            System.out.println("2.数学计算开始中"+(10/5));
        } catch (ArithmeticException e) {
            System.out.println("出现异常,除数有误");
        }finally {
            System.out.println("4.finally代码块");
        }
        System.out.println("3.数学计算完成..");
    }
}

运行结果:
在这里插入图片描述

范例:

public class Test {
    public static void main(String[] args) {
        System.out.println(test(1));
    }
    public static int test(int num){
        try {
            System.out.println("1.*****"+(10/num));
            return 1;
        } catch (ArithmeticException e) {
            System.out.println("2.########");
            return 2;
        }finally {
            System.out.println("3.&&&&&&&&");
            return 3;
        }
    }
}

在这里插入图片描述
不管此时是否产生异常,最终都要执行finally程序代码,所以finally会作为程序统一出口。
观察上段代码,得出结论,只要finally中有return语句就不会再执行try、catch语句中的return语句;当finally中没有return语句的时候,才会执行try、catch中的return语句。

范例:初始化参数进行数学运算

public class Test {
    public static void main(String[] args) {
        System.out.println("1.数学计算开始前..");
        try {
            int num1=Integer.parseInt(args[0]);
            int num2=Integer.parseInt(args[1]);
            System.out.println("2.数学计算开始中"+(num1/num2));
        } catch (ArithmeticException e) {
            System.out.println("出现异常,除数有误");
        }
        System.out.println("3.数学计算完成..");
    }
}

观察上述代码,可能会存在一下问题:

  • 用户没有输入初始化参数:ArrayIndexOutOfBoundsException
  • 用户输入的不是数字:NumberFormatException
  • 被除数为0:ArithmeticException
    以上代码我们发现,通过catch捕获异常的时候如果,没有捕获指定异常,程序依然无法进行处理,现在最直白的解决方案就是使用多个catch。
    范例:多个catch块
public class Test {
    public static void main(String[] args) {
        System.out.println("1.数学计算开始前..");
        try {
            int num1=Integer.parseInt(args[0]);
            int num2=Integer.parseInt(args[1]);
            System.out.println("2.数学计算开始中"+(num1/num2));
        } catch (ArithmeticException e) {
            e.printStackTrace();
        }
        catch (NumberFormatException e){
            e.printStackTrace();
        }
        catch(ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
        }
        System.out.println("3.数学计算完成..");
    }
}

问题是解决了,可以这样一个一个处理太麻烦了,想有没有什么方法可以统一概括这一类的异常?我们联想到他们的父类RuntimeException
范例:

public class Test {
    public static void main(String[] args) {
        System.out.println("1.数学计算开始前..");
        try {
            int num1=Integer.parseInt(args[0]);
            int num2=Integer.parseInt(args[1]);
            System.out.println("2.数学计算开始中"+(num1/num2));
        }
        //向上转型
       catch (RuntimeException e) {
            e.printStackTrace();
        }
        System.out.println("3.数学计算完成..");
    }
}

观察上述代码,因为用户没有输入初始化参数、用户输入的不是数字、被除数为0这三个异常是非受查异常,所以它们的父类是RuntimeException类,我们可以进行向上转型操作,其定义的对象就囊括了所有非受查异常。

throws关键字

在进行方法定义的时候,如果要告诉调用者本方法可能产生哪些异常,就可以使用throws方法进行声明。即,如果该方法出现问题后不希望进行处理就使用throws抛出。

范例:使用throws定义方法

public class Test {
    public static void main(String[] args) {
        try {
            System.out.println(div1(11,0));
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("2.$$$$$");
    }
    //这里抛出的是受查异常,所以调用者必须处理
    public static int div1(int a,int b) throws Exception{
       int num=a/b;
        System.out.println("1.******");
        return num;
    }
}

运行结果:
在这里插入图片描述
如果调用了throws声明方法,那么调用时必须明确的使用try…catch…进行捕获,因为该方法有可能产生异常,所以必须按照异常的方式进行处理。
再观察上面的运行结果我们发现没有输出1.****,说明调用throws声明方法,方法中异常语句以下的语句不再执行。
主方法本身也属于一个方法,所以主方法上也可以使用throws进行异常抛出,这个时候如果产生了异常就会交给JVM处理。
范例:主方法抛出异常

public class Test {
    public static void main(String[] args)throws Exception  {
            System.out.println(div1(11,0));
        System.out.println("2.$$$$$");
    }
    public static int div1(int a,int b) throws Exception{
       int num=a/b;
        System.out.println("1.******");
        return num;
    }
}

运行结果:
在这里插入图片描述

throw关键字

throw是直接编写在语句之中,表示人为进行异常的抛出,即异常对象由用户产生而非JVM产生。一般与自定义异常搭配使用。
范例:使用throw产生异常类对象。

public class Test {
    public static void main(String[] args)throws Exception  {
        try {
        //实例化了一个异常对象
            throw new Exception("自己抛出个异常");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

throw与自定义异常搭配使用

自定义异常:我们通过自己的需求自己定义的一个异常类。在Java中,很多时候系统提供的异常信息不够我们使用,这个时候我们就要自己定义一个异常类,结合throw关键字来抛出异常
范例:throw与自定义异常搭配使用

//定义一个加法异常类
class AddExcaption extends Exception{
    String str;
    public AddExcaption(String str){
        super(str);
    }
}
public class Test {
    public static void main(String[] args)throws Exception  {
       int num1=1;
       int num2=1;
       if(num1+num2==2){
           AddExcaption add=new AddExcaption("错误的相加操作");
           add.printStackTrace();
       }
       else{
           System.out.println(num1+num2);
       }
    }
}

throw和throws的区别

  • throw用于方法内部,主要表现在手工抛出异常,和自定义异常类结合着使用。
  • throws主要在方法声明声明上使用,明确告诉用户本方法可能产生异常,同时该方法可能不处理此异常。

Exception与RuntimeException区别

  • Exception是RuntimeException的父类,使用Exception定义的异常都要求必须使用异常处理,而使用RuntimeException定义的异常可以由用户选择性的来进行异常处理。
    常见的RuntimeException:ClassCastException、NullPointerException等。

断言assert

断言是从JDK1.4开始引入的概念。断言指的是当程序执行到某些语句之后其数据的内容一定是约定的内容,否则就中断程序。
语法:assert 布尔表达式:“返回false执行的代码块”

范例:观察断言

public class Test {
    public static void main(String[] args){
       int num=10;
       assert num==50:"错误:num应该等于50";
        System.out.println(num);
    }
}

如果想让断言起作用,就必须使用-ea的参数,启用断言
idea操作:run->Edit con…->VM …->-ea
运行结果如下:
在这里插入图片描述
实际上断言的意义并不是很大,Java之所以引用主要是为了与c++兼容,开发中不提倡使用断言。
推荐一个查找异常的网站https://stackoverflow.com/(纯英文的~)好好学习英语,英语真真真特别重要。很多csdn翻译的有的异常信息是有错误的,所以只要你英语够强,你就可以自己给自己翻译,加油老铁们!!!

猜你喜欢

转载自blog.csdn.net/HL_HLHL/article/details/84001058