zoukankan      html  css  js  c++  java
  • Java基础—异常

    一、概念

      异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。

      异常体

      Throwable:所有异常类的超类

       Error:它表示不希望被程序捕获或者是程序无法处理的错误

      Exception:它表示用户程序可能捕捉的异常情况或者说是程序可以处理的异常  

        其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常。

        Java异常又可以分为不受检查异常(Unchecked Exception)和检查异常(Checked Exception)。

          检查异常属于编译时异常,也就是编译时就会出现的异常,必须进行处理(try catch/throws)

          而不受检查的异常属于运行时异常,在编译期间不可查,在程序控制范围之外。

      java中常见异常请参见http://blog.csdn.net/liu_jian140126/article/details/50517001

       更形象更全面的版本http://www.importnew.com/16725.html

    二、异常处理机制

        了解异常处理机制之前,先要了解异常情形(exception condition),它是指阻止当前方法或作用域继续执行的问题。

    所以,异常发生的时候,作用域后续的代码无法继续执行!

        抛出异常后,会有几件事随之发生。首先,是像创建普通的java对象一样将使用new在堆上创建一个异常对象;

    然后,当前的执行路径(已经无法继续下去了)被终止,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序

      更多异常机制的讲解,参见(推荐!):http://www.cnblogs.com/Qian123/p/5715402.html

        异常处理机制主要分为两大类——捕获异常抛出异常

      1.捕获异常

      常用捕获语句结构:

        try {
                //可能发生异常的代码
            } catch (Exception e1) {
                // 捕获异常后的处理代码
            } catch (Exception e2) {
                // 捕获异常后的处理代码
            } finally {
                // 总是会执行的代码(可选)
            }

     注意点:

       1.try语句块中的是可能出现异常的语句;try中声明的变量生命周期仅在try语句块中有效,通常,我们将声明写在try之前以提高生命周期!

      2.catch语句块是捕获异常后的异常处理;发生异常后catch语句依次检查(catch语句捕获的异常应当是逐级捕获,先捕获小的异常,后捕获大的异常),当某个异常块被捕获后,其它语句块便被旁路。

        

    Exception常见的两个方法:

          e.printStackTrace()——打印异常的堆栈

          e.getMessage()——得到异常消息(传入的message属性的信息)

        详细的介绍可以参见API,并查阅相关的源码查看

      3.finally语句无论是否发生异常都会执行,如果之前代码有return语句,那么会在return语句之前执行,通常,可以用来做一些资源关闭的操作!

      捕获的异常的执行顺序可以参考以下的小例子:

      public static void main(String[] args) {
            int i = 100;
            try {
                i = i + 10;
                System.out.println("异常发生前+10......" + i);
                i = 1 / 0;
                i = i + 10;
                System.out.println("异常发生后+10...." + i);
            } catch (Exception e) {
                i = i + 10;
                System.out.println("捕获异常并+10......" + i);
                System.out.println(e.getMessage());
            } finally {
                i = i + 10;
                System.out.println("finally语句块执行+10..." + i);
            }
            System.out.println("异常处理后...." + i);
        }

      之前我们说过,发生异常后,当前作用域代码无法执行!但是异常处理完毕后的代码可以正常运行(不然我们要异常处理干嘛呢),但是只有异常发生之前对变量的修改是有效的,异常发生后对变量的操作将不会执行!

       

       上面的try_catch的模型,一般用于非运行时异常(checked Exception),运行时异常一般不需要手动进行处理

       2.抛出异常

      在方法签名上声明抛出的异常(自动抛出一个异常对象):

      对于异常情形,已经无法继续下去了,因为在当前环境下无法获得必要的信息来解决问题,你所能做的就是从当前环境中跳出,并把问题提交给上一级环境,这就是抛出异常时所发生的事情。

      方法只是抛出异常,谁调用谁负责处理(要么继续外抛,要么try_catch进行捕获处理)

      

       //其中file()方法选择了将异常抛出,那么在发生异常的时候就会抛出一个异常的对象!调用它的main方法就必须处理:要么继续在方法声明上抛出,要么进行try_catch

      //如果方法中抛出了具有父子关系的异常,那么如果异常是统一处理的,可以只抛出大的异常,捕获大的异常,统一处理,想不同的异常区别处理,可以遵循catch块的原则,分别处理!

      手动抛出一个异常:

      看实例:

     public static void main(String[] args) {
            inputNumber(0);
        }
    
        // 抛出异常
        public static void inputNumber(int num){
            if (num == 1) {
                System.out.println("输入了:1");
            } else {
                // 手动抛出异常
                throw new RuntimeException("传入的不是1!(只能传入1!)");
            }
        }

      

      抛出异常就是以上两种方式:在方法声明处抛出一个异常的类型!——throws

                   在代码处手动抛出一个异常对象!——throw

      throw出的异常一般是运行时异常(RuntimeException及其子类等),如果抛出了非运行时异常(例如直接抛出Exception

    :throw new Exception(),那它可能不是一个运行时异常),还需要处理!

    三、自定义异常

      我们采用的是继承异常类(Exception或者RuntimeException)的形式:

    public class MyException extends RuntimeException{

      但是异常类怎么写呢?我们既然也是定义的异常类,那么我们可以看看它的父类怎么写的:

      

      原来就是一个序列号再加几个重载的构造器吖!

      序列号是用于序列化的,构造器中的具体内容可以点击源码查看到,像message其实就是Throwable中的 一个 属性detilMessage,用于异常提示的。

      那我们仿造它来一个: 

    public class MyException extends RuntimeException{
        static final long serialVersionUID = -7034868990745766939L;
    
        public MyException() {
        }
    
        public MyException(String message) {
            super(message);
        }
    }

      把上面抛出的异常换成我们实现的自定义异常(RuntimeException的子类)

      public static void main(String[] args) {
            inputNumber(0);
        }
    
        // 抛出异常
        public static void inputNumber(int num){
            if (num == 1) {
                System.out.println("输入了:1");
            } else {
                // 手动抛出异常
                throw new MyException("来自自定义异常:传递的参数只能为:1!");
            }
        }

       

      当然,以上只是根据父类编写一个基本的自定义异常,我们还可以自定义更加丰富的异常类(异常类也是一个普通的类)

    public class MyException extends RuntimeException{
        static final long serialVersionUID = -7034868990745766939L;
        private double balance;
    
        public MyException() {
        }
    
        public MyException(String message, double balance) {
            super(message);
            this.balance = balance;
        }
    
        public double getBalance() {
            return balance;
        }
    }

      像这样可以实现一些自定义的逻辑,抛出异常时也可以携带自定义的信息:throw new MyException("余额不足",-1);

    再通过e.getBalance()取得自定义的信息。

  • 相关阅读:
    课后作业07--二分法查找算法代码
    检索03 -- 二分法查找
    课堂随笔05--冒泡排序
    课后作业 06 -- 小数后几位精确判断并输出
    课后作业 05 -- 输出一段带字母与数字的随机数
    课后作业 04 --DateTime应用,判断多久后生日之类
    检索02--随机数种子的一些概念和理解
    课堂随笔04--关于string类的一些基本操作
    P1174 互素
    P1001 第K极值
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6663550.html
Copyright © 2011-2022 走看看