关于异常
异常:就是程序在运行时出现不正常情况。
异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述。并封装成对象。其实就是java对不正常情况进行描述后的对象体现。
对于问题的划分:两种:一种是严重的问题,一种非严重的问题。
对于严重的,java通过Error类进行描述。对于Error一般不编写针对性的代码对其进行处理。
对与非严重的,java通过Exception类进行描述。对于Exception可以使用针对性的处理方式进行处理。
ERROR和Exception都继承于Throwable
异常的处理代码
try
{
需要被检测的代码;
}
catch(异常类 变量)
{
处理异常的代码;(处理方式)
}
finally
{
一定会执行的语句;一般用于资源关闭操作
}
class MyMath {
public static int divide(int num1, int num2) {
int res = num1 / num2;
return res;
}
}
public class ExceptionTest {
public static void main(String[] args) {
int res = MyMath.divide(4, 0);
System.out.println(res);
}
}
上面代码中被除数为0,编译器通过,但实际运行结果:出现异常并且在异常处程序终止运行
现在在divide方法上将该可能产生的异常“抛出”,抛给调用者,这样谁调用,谁就必须处理该异常(要么捕获,要么继续抛出)。
class MyMath {
public static int divide(int num1, int num2) throws Exception{
int res = num1 / num2;
return res;
}
}
捕获该异常:
public class ExceptionTest {
public static void main(String[] args) {
int res=0;
try {
res = MyMath.divide(4, 0);
System.out.println(res);
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("提示用户除数不能为0");
e.printStackTrace();//此处是打印异常堆栈信息方法,打印结果包括具体异常类、位置等信息
}
finally{
System.out.println("无论是否有异常发生都执行的代码区域");
}
}
}
如图,finnaly代码块内的代码总会执行。
需要说明的是ArithmeticException继承于RunTimeException,而RunTimeException是一种特殊的异常,如果调用浸泡出该异常或该异常子类的异常的类方法,编译器不会强制进行捕获或者再抛给外部。因为RunTimeException异常的原因一般不是有程序的代码造成的而是传入的数据不符合规则,如被出入本应不能为0。因此不需要被强制进行处理,但是也可以视为普通异常进行相关操作。
下面的例子中可能出现的异常有两种(此时视RunTimeException为一般异常也对其处理)
class MyMath {
public static int divide(int num1, int num2) {
int[] arr = new int[num1];
System.out.println(arr[9]);
return num1/num2;
}
}
除了
ArithmeticException外,还可能抛出数组越界异常ArrayIndexOutOfBoundsException(属于RunTimeException
),此时依然可以只抛出Exception类,但是这两种异常情况出现后,处理方式应该有所区别,分别对待。所以仅抛出Exception就不行了。
应该将两种具体异常跑出来,让调用者分别做出处理办法
class MyMath {
public static int divide(int num1, int num2) throws ArithmeticException,ArrayIndexOutOfBoundsException {
int[] arr = new int[num1];
System.out.println(arr[9]);
return num1/num2;
}
}
处理方式:
public class ExceptionTest {
public static void main(String[] args) {
int res = 0;
try {
res = MyMath.divide(4, 0);
System.out.println(res);
} catch (ArithmeticException e) {
// TODO: handle exception
System.out.println("被除数不能为0");
} catch (ArrayIndexOutOfBoundsException e) {
// TODO: handle exception
System.out.println("数组越界了");
}finally{
System.out.println("最后总会执行");
}
}
}
现在假定需求除数为负数也是不应该出现的,假如出现除数为负数,程序就停止且抛出异常。但是这是一种自己定义的异常规则。现有的异常类中并没有与之对应的异常类,此时可以定义一个自定义异常专门描述这种情况。
public class MinusException extends Exception {
public MinusException(String msg) {
super(msg);
}
}
使用该异常
class MyMath {
public static int divide(int num1, int num2) throws MinusException {
if (num2 < 0)
throw new MinusException("/ by minus:"+num2);
return num1 / num2;
}
}
public class ExceptionTest {
public static void main(String[] args) {
int res = 0;
try {
res = MyMath.divide(4, -1);
System.out.println(res);
} catch (MinusException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
System.out.println("最后总会执行");
}
}
}
抛出自定义异常:exception.MinusException: / by minus:-1
异常在实际开发中
class FailureException extends Exception
{
}
public void method()throws NoException
{
连接数据库;
数据操作;//throw new SQLException();
关闭数据库;//该动作,无论数据操作是否成功,一定要关闭资源。
try
{
连接数据库;
数据操作;//throw new SQLException();
}
catch (SQLException e)
{
会对数据库进行异常处理;
throw new FailureException();//告知调用者操作失败
}
finally
{
关闭数据库;
}
}
异常的三个形式:
// 第一个格式:
try {
} catch (Exception e) {
}
// 第二个格式:
try {
} catch (Exception e) {
} finally {
}
// 第三个格式:
try {
} finally {
}
第三种形式没有对异常进行捕获,所以当非RunTimeException时,必须声明到方法上。如果发生异常,finally总执行。
关于子父类间的异常
子父类间异常的原则
1,子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
2,如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
3,如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
如下:
class AException extends Exception{
}
class CException extends Exception{
}
class DException extends Exception{
}
class BException extends AException{
}
class Superclass{
public void show() throws AException{
}
}
class SubClass extends Superclass{
@Override
public void show() throws BException {
// TODO Auto-generated method stub
super.show();
}
}
如果子类抛出DException,父类抛出AEXception和CEXception
编译器会通知Exception DException is not compatible with throws clause in Superclass.show()
class Superclass{
public void show() throws AException,CException{
}
}
class SubClass extends Superclass{
@Override
public void show() throws DException {//抛出的DException非父类抛出的子集 编译器不通过
// TODO Auto-generated method stub
super.show();
}
}
总结一句话:下一代一定要比上一代更“好”,即抛出的异常少于等于父类,同时也不产生对于父类更新的异常。