异常与异常处理

异常简介

  • java异常是java提供的用于处理程序中错误的一种机制。
  • 有异于常态,和正常情况不一样,有错误出现。从编程上来讲,把阻止当前方法或作用域,称为异常。
  • 涉及良好的程序应该在异常发生时,提供处理这些错误的方法,使得程序不会因为异常的出现而阻断或产生不可预见 的结果。
  • java程序的执行过程中如果出现异常事件,就会生成一个异常类对象,该异常类对象封装了异常事件的信息,并将提交给java运行时系统,这个过程称为抛出(throw)异常。
  • 当java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。
  • 当异常发生时,程序会中止当前的流程,根据获取异常的类型去执行相应的catch代码块。

异常的体系结构

  • 1.Java中的所有不正常类都继承于Throwable类。Throwable主要包括两个大类,一个是Error类,另一个是Exception类;
  • 2.其中Error类中包括虚拟机错误和线程死锁,一旦Error出现了,程序就彻底的挂了,被称为程序终结者;
  • 3.Exception类主要指编码、环境、用户操作输入出现问题,Exception主要包括两大类,非检查异常(RuntimeException)和检查异常(需要手动添加捕获和处理语句,有:文件异常、SQL异常等)
  • 4.RuntimeException异常主要包括以下四种异常:空指针异常、数组下标越界异常、类型转换异常、算术异常。

使用try..catch..finally实现异常处理

  • 处理异常
    try..catch以及try..catch..finally
    语法:
try {
//一些会抛出异常的方法
}
catch (Excepotion1 e){
//处理该异常的代码块
}
catch (Excepotion2 e){
//处理该异常的代码块
}
…
(n个catch块)//如果没有异常产生,所有的catch代码块都会被略过不执行!finally{
//资源回收块
}

注意:

  • 异常处理语法结构中,只有try块是必须的。也就是说,如果没有try块,则不能有后面的catch块和finally块;
  • catch块和finally块都是可选的,但catch块和finally块至少出现其中之一,也可以同时出现;
  • 可以有多个catch块,捕获父类异常的catch块必须位于捕获子类异常的后面;
  • 不能只有try块,既没有catch块,也没有finally块;
  • 多个catch块必须位于try块之后,finally块必须位于所有的catch块之后。
    下面看一个具体的例子:
package com.xupt.test;

public class TryCatchTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        TryCatchTest tct=new TryCatchTest();
        int result=tct.test();
        System.out.println("test()方法执行完毕!返回值为:"+result);
        int result2=tct.test2();
        System.out.println("test2()执行完毕!");

    }
/**
 * divider除数
 * result结果
 * try—catch捕获while循环
 * 每次循环,divider减一,result=result+100/divider
 * 如果:捕获异常,打印输出“抛出异常啦!”,并返回-1
 * 否则:result
 * @return
 */
    public int test(){
        int divider=10;
        int result=100;
        try{
            while(divider>-1){
                divider--;
                result = result + 100/divider;
            }
            return result;
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("循环抛出异常了!");
            return -1;
        }
    }
    /**
     * divider除数
     * result结果
     * try—catch捕获while循环
     * 每次循环,divider减一,result=result+100/divider
     * 如果:捕获异常,打印输出“抛出异常啦!”,并返回-1
     * 否则:result
     * finally:打印输出:“这是finally!”,同时打印输出result的值
     * @return
     */ 
public int test2(){
    int divider=10;
    int result=100;
    try{
        while(divider>-1){
            divider--;
            result = result + 100/divider;
        }
        return result;
    }catch(Exception e){
        e.printStackTrace();//将该异常的跟踪栈信息输出到标准错误输出
        System.out.println("循环抛出异常了!");
        return result=999;
    }   
    finally{
        System.out.println("这是finally!");
        System.out.println("我是result!值是:"+result);
    }
    }
}

输出结果:

java.lang.ArithmeticException: / by zero
    at com.xupt.test.TryCatchTest.test(TryCatchTest.java:29)
    at com.xupt.test.TryCatchTest.main(TryCatchTest.java:8)
循环抛出异常了!
test()方法执行完毕!返回值为:-1
java.lang.ArithmeticException: / by zero
    at com.xupt.test.TryCatchTest.test2(TryCatchTest.java:54)
    at com.xupt.test.TryCatchTest.main(TryCatchTest.java:10)
循环抛出异常了!
这是finally!
我是result!值是:999
test2()执行完毕!

注意:异常捕获时,一定要记住先捕获小异常,再捕获大异常!不仅应该把Exception类对应的catch块放在最后,而且所有父类异常的catch块都应该排在子类异常catch块的后面,否则将出现编译错误。看如下代码片段:

try {
statements…
}catch(RuntimeException e){//1
System.out.println("运行时异常");
}catch(NullPointerException ne){//2
System.out.println("空指针异常");
}

上面的代码中有两个catch块,前一个catch块捕获RuntimeException异常,后一个catch块捕获NullPointerException 异常,编译上面代码时将会在2处出现已捕获到异常java.lang.NullPointerException 的错误,因为1处的RuntimeException已经包含了NullPointerException 异常,所以2处的catch块永远也不会获得执行的机会。

java中的异常抛出以及自定义异常

java中的异常抛出
* throw:将产生的异常抛出
* throws:声明将要抛出何种类型的异常(声明)

public void 方法名(参数列表) throws 异常列表{
//调用会抛出异常的方法或者:throw new Exception();
}

具体形式:

public void divide(int one,int two) throws Exception{
if(two==0){
throw new Exception("两数相除,除数不能为0!");
}else{
System.out.println("两数相除,结果为:"+one/two);
}
}

自定义异常

  • 用throws声明方法可能抛出自定义的异常,并用throw语句在适当的地方抛出自定义的异常。
public class Test{
    public void regist(int num) throws MyException{
        if (num<0){
            throw new MyException("人数为负值,不合理",3);
        }
        System.out.println("登记人数"+num);
    }

    public void manager(){
            try{regist(100);}
            catch(MyException e){
                    System.out.println("登记失败,出错类型码="+e.getId());
                        e.printStackTrace();
                }
                System.out.print("操作结束");

        }

        public static void main(String[] args){
            Test t = new Test();
            t.manager();
            }
}
class MyException extends Exception{
    private int id;
    public MyException(String message,int id){
        super(message);
        this.id=id;
        }
        public int getId(){
            return id;
            }
    }

java中的异常链

对于一个真实的企业级应用而言,常常有严格的分层关系,层与层之间有着非常清晰的划分,上层功能的实现,严格依赖于下层的API,也不会跨层访问。分层结构从下到上一次为:

  • 持久层:保存数据
  • 中间层:实现业务逻辑
  • 表现层:用户界面

当业务逻辑层访问持久层出现SQLException异常时,程序不应该把底层的SQLException异常传到用户界面,有如下两个原因:
* 对于正常用户而言,他们不想看到底层SQLException异常,SQLException异常对他们使用该系统没有任何帮助;
* 对于恶意用户而言,将SQLException异常暴露出来不安全。
把底层的原是异常直接传给用户是一种不负责任的表现。通常的做法是:程序先捕获原始异常,然后抛出一个新的业务异常,新的业务异常中包含了对用户的提示信息,这种处理方式被称为异常转译。
假设程序需要实现工资计算的方法,则程序应该采用如此啊结构的代码来是实现该方法:

import javax.security.sasl.SaslException;

public class calSal throws SalExecption{
    try {
        //实现结算工资的业务逻辑
        ……
    } catch (SQLException sqle) {
        // TODO: handle exception
        //把原始异常记录下来,留给管理员
        ……
        //下面异常中的message就是对用户的提示
        throw new SaslException("访问底层数据库出现异常");
    }
    catch (Exception e) {
        // TODO: handle exception
        //把原始异常记录下来,留给管理员
        ……
        //下面异常的message就是对用户的提示
        throw new SaslException("系统出现未知异常");
    }
}

这种把原始异常信息隐藏起来,仅向上提供必要的异常提示信息的处理方式,可以保证底层异常不会扩散到表现层,可以避免向上暴露太多的实现细节,这完全符合面向对象的封装原则。
这种把捕获一个异常然后接着抛出另一个异常,并把原始异常信息保存下来是一种典型的链式处理,也被称为“异常链”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值