java的异常和处理详解
异常,用大白话讲,就是在程序运行期间发生的不正常情况。大家都知道java语言最大的特点就是面向对象的思想,它会把一个事物用类的形式去封装,所以异常也不例外。java就是通过这种思想将问题封装成了对象。在java中,描述这些不正常情况的类就称为异常类。
一、异常分类
话不多说,先看一张图吧
从图上,可以看到异常中的父类就是Throwable类,该类就是将所有的问题的共性向上抽取,而形成的一个异常体系。该体系最大的特点就是Throwable及其子类都具有可抛性。
注意:无论是Error还是Exception,问题发生就应该让调用者知道并处理。
1、Error类
该类一般是不可处理的,就是没有办法处理这种错误,这个问题出现一般不针对性的处理,只能直接修改程序。特点就是由jvm抛出的严重性的问题。
2、Exception类
Exception体系中一般分为两类:一类是编译时被检测异常,另一类是编译时不检测异常。
1.编译时被检测异常;只要是Exception和其子类都是,(除了特殊子类RuntimeException体系)这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的针对性处理方式。
2.编译时不检测异常(运行时异常):就是Exception中的RuntimeException和子类,
这种问题的发生,无法让功能继续,运算无法进行,更多是因为调用者的原因导致的或者引发了内部状态的改变导致的。这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行修正。
二、异常的处理
我们一般写程序多多少少都会出现异常,那异常出现了我们怎么处理呢。有两个处理办法,对其进行捕获或者声明以便抛出。
1、可抛性
那么,可抛性是什么?什么样才算是可抛性呢?其实说到底就是使用两个关键字体现的:throw和throws,可以说,凡是可以被这两个关键字所操作的类和对象都具有可抛性这一特点。举个例子吧:
public static void main(String[] args) {
String str = "throw";
if(str.equals("throw")) {
throw new NumberFormatException();
} else {
System.out.println(str);
}
}
public class Demo(){
public static void test() throws NumberFormatException {
String str = "throws";
System.out.println(Double.parseDouble(s));
}
public static void main(String[] args) {
try {
test();
} catch (NumberFormatException e) {
e.printStackTrace();
System.err.println("非数据类型不能强制类型转换。");
}
}
throw和throws的区别:
1,throws使用在函数上;throw使用在函数内
2,throws抛出的是异常类,可以抛出多个,用逗号隔; throw抛出的是异常对象。
2、异常的捕获
对异常的捕获,就是对这种异常进行针对性处理的方式,具体的格式如下:
try
{
//需要被检测异常的代码
}
catch(异常类 变量)//该变量用于接受发生的异常对象
{
//处理异常的代码
}
finally
{
//一定会被执行的代码
}
那么就来加个例子吧:
class FuShuIndexException extends Exception
{
FuShuIndexException();
{}
FuShuIndexException(String msg)
{
super(msg);
}
}
class Demo
{
public int method(int[] arr,int index)throws FuShuIndexException
{
if(index<0)
{
throw new FuShuIndexException("数组的角标不能为负数!"+index);
}
return arr[index];
}
}
class ExceptionDemo2
{
public static void main(String[] args)
{
int[] arr=new int[3];
Demo d=new Demo();
try
{
int num=d.method(arr,30);
System.out.println("num="+num);
}
catch(FuShuIndexException e)
{
e.printStackTrace();//jvm默认的异常处理机制就是调用异常对象的这个方法
System.out.println("负数角标异常!!!");
}
System.out.println("over");
}
}
这里要注意一点:当进行多catch处理的时候,父类的catch要放在最下面。
3、异常处理的原则
既然对待异常,有两种所处理的方法,我们到底应该具体使用哪一个呢?
1.函数内容如果抛出需要检测的异常,那么函数上必须要声明。否则必须在函数内用try catch捕捉,否则编译失败。
2.如果调用到了声明异常的函数,要么try catch要么throws,否则编译失败。
3.什么时候catch,什么时候throws呢?
功能内容可以解决,用catch
解决不了,用catch告诉调用者,由调用者解决
4。一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性的处理。内部有几个需要检测的异常,抛几个,就catch几个。
4、自定义异常
其实java语言已经帮我们写好了问题出现所要抛出的异常,那我们怎么可以自己写一个异常呢。道理也很简单,我们可以自己写一个类,然后继承异常体系就over了。因为只有成为异常体系的子类,才具有可抛性,也就可以被throw和throws操作。
class FuShuIndexException exteds Exceptio
{
//空的构造函数
FuShuIndexException(){}
FuShuIndexException(String msg)
{
super(msg);
}
}
class Demo
{
public int method(int[] arr,int index)throws FuShuIndexException
//声明这个throws FuShuIndexException的目的就是让调用者来处理这个问题。
{
if(index<0)
{
throw new FuShuIndexException("数组的角标不能为负数"+index);
}
return arr[index];
}
}
class ExceptionDemo2
{
public static void main(String[] args)throws FuShuIndexExceptions
{
int[] arr=new int[3];
Demo d=new Demo();
int num=d.method(arr,3);
}
}
三、异常的注意事项
1.子类在覆盖父类方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类。
2.如果父类抛出多个异常,那么子类只能抛出父类异常的子集
听起来是不是有点绕口,简单说:就是子类覆盖父类只能抛出父类的异常或者子类或者子集。
注意:如果父类的方法没有抛出异常,那么子类覆盖时绝对不能抛,就只能try。