java之异常



首先来说说什么是异常。
在《java编程思想》中这样定义 异常:阻止当前方法或作用域继续执行的问题。虽然java中有异常处理机制,但是要明确一点,决不应该用”正常”的态度来看待异常。绝对一点说异常就是某种意义上的错误,就是问题,它可能会导致程序失败。之所以java要提出异常处理机制,就是要告诉开发人员,你的程序出现了不正常的情况,请注意。

比如大家经常写java代码,会碰到到IndexOutOfBoundsException(数组越界异常),会碰到的NullPointerException(空指针异常)等。这种必须编译之后才能发现的错误称为异常。java把异常都看为类,每当发现一个异常就会创建这个异常的实例。

java异常类结构如下

异常结构

这里需要说明是三个类

Error:出现这种异常基本都是运行java程序的环境出现的问题。比如jvm崩溃,断网等。像这类异常通常指示合理的应用程序不应该试图捕获的严重问题。当出现这种异常时,通常不要试图去捕获,因为基本是程序处理不了的问题。

Exception:程序可以处理的异常

RuntimeException:这个Exception的子类必须单独提出来说一说。这类异常被称为运行时异常。像这类异常是编译器的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。比如IndexOutOfBoundsException(数组越界异常),会碰到的NullPointerException(空指针异常),是RuntimeException的子类,当出现这种异常时,编译器既不会提醒你抛出异常,也不会提醒你需要捕获异常。

除了这些java自己设置的异常。我们有时候还需要自己定义异常,这种异常通常是符合java语法,但是不符合我们程序的业务逻辑,这种时候就需要自己创建一个异常了。举个简单的例子:要求用户输入自己的昵称,如果用户输入的是一些非法字符(比如骂人的话),这个时候就需要自定义一个异常,当程序一发现这种异常,就将它抛出。

Java规定:对于可查异常必须捕捉、或者声明抛出。允许忽略不可查的RuntimeException和Error


代码示例:
自己主动创建异常:


/**
 * 使用该类测试抛出异常的处理方式
 * 通常遇到两种情况需要抛出异常给调用者:
 * 1.程序执行遇到错误,但是该异常不应当由当前代码来处理时,
 * 应当抛给调用者(流程决策者)来处理
 * 2.当遇到一个满足语法要求(程序本身没有异常)但是该情况不符合业余逻辑要求时,
 * 可以主动创建一个异常来通知调用者不应该这样做。
 * @author Analyze
 *
 */
public class Person {
    private int age;

    public int getAge() {
        return age;
    }
    /**
     * 通常,一个方法中使用throw抛出什么异常,方法上就应当使用throws定义该异常的抛出以告知调用者需要处理该异常。
     * 但是只有一类异常例外,即RuntimeException及其子类异常
     * @param age
     * @throws Exception
     */
    public void setAge(int age) throws IllegalAgeException  {
        if(age<0||age>200){
            throw new IllegalAgeException("年龄不在合理范围内"+age);
        }
        this.age = age;
    }

}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
/**
 * 自定义异常,通常用来定义业务逻辑层级的异常
 * 
 * 年龄不合法异常
 * @author Analyze
 *
 */
public class IllegalAgeException extends Exception {

    /**
     * 因为父类序列化了,所以子类最好也能序列化
     * 设置版本号
     */
    private static final long serialVersionUID = -6878617771685349880L;

    public IllegalAgeException() {
        super();
        // TODO Auto-generated constructor stub
    }

    public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
        // TODO Auto-generated constructor stub
    }

    public IllegalAgeException(String message, Throwable cause) {
        super(message, cause);
        // TODO Auto-generated constructor stub
    }

    public IllegalAgeException(String message) {
        super(message);
        // TODO Auto-generated constructor stub
    }

    public IllegalAgeException(Throwable cause) {
        super(cause);
        // TODO Auto-generated constructor stub
    }



}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

java的异常处理机制

在 Java 应用程序中,异常处理机制为:抛出异常,捕捉异常。

抛出异常:当发现异常时,在当前方法内不去解决,而是继续丢出去,交给调用这个方法的人去“擦屁股”。关键字:throws

捕捉异常:通过try-catch语句或者try-catch-finally语句实现。
在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
简单点来说,需要将有可能发生异常的语句用try-catch(异常处理器)包住。在 try中尝试执行有可能发生错误的语句,当发生异常时,查看当前异常与catch中的异常有没有一样的异常或者是catch中异常的子类。如果有,那么JVM认为开发人员意识到这个异常,就会交给开发人员去解决。如果没有,那么JVM就认为开发人员没有意识到这个异常,继续将该异常抛出。如果在程序中一直没有处理这个异常(意味着将异常抛给主函数),那么在程序运行时JVM就将该程序杀死(程序终止)。


代码实例:

java异常捕获机制中的try-catch

public static void main(String[] args) {
        System.out.println("程序开始了");
        try{
            String str="";
            /*
             * 当虚拟机指定到一处错误时,会创建一个该类型异常的实例,
             * 并将完成的错误报告设置好,然后将该异常抛出
             */
            System.out.println("len:"+str.length());

            System.out.println(str.charAt(0));

            System.out.println(Integer.parseInt(str));
            /*
             * 在try语句块中出错代码以下的代码都不再被执行
             */
            System.out.println("!!!!!");
        }catch(NullPointerException e){
            /*
             * catch块内容执行完毕就退出异常捕获机制
             * 继续向下执行代码
             */
            System.out.println("出现了空指针异常!!");
        /*
        * catch块可以定义多个,针对不同异常若有不同的处理手段,
        * 可以定义多个catch分别捕获这些异常
        */
        }catch(StringIndexOutOfBoundsException e){
            System.out.println("字符串下标越界了!");
        /*
         * 应当有一个好习惯,在最后一个catch中捕获Exception
         */
        }catch(Exception e){
            System.out.println("反正就是出错了");
        }

        System.out.println("程序结束了");
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

finally块
finally块被定义咋异常捕获机制的最后一块代码块上。
finally可以保证内部代码一定被执行。无论try块中的代码是否抛出异常。
所以通常会把诸如释放内存等操作放在finally块中。
finally可以直接跟在try块后,或者会有一个catch块之后

public static void main(String[] args) {
        try{
            String str=null;
            System.out.println(str.length());
        }catch(Exception e){
            System.out.println("程序出错了");
        }finally{
            System.out.println("finally块代码被执行了");
        }

    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

有一道关于finally块的经典面试题,通过这个题跟能说明finally块一定会被执行的问题

public static void main(String[] args) {

        System.out.println(
            test("0")+","+
            test(null)+","+
            test("")
        );
        /**
         * !!注意:输出为3,3,3
         * 代码执行过程为:
         * 当执行test("0")时,调test方法
         * 看见返回值为int型变量,会自己先定义一个int型的变量(例如变量名为r)
         * 当执行到return str.charAt(0)-'0';这句话时,把return后计算的值赋值给r
         * 然后一层一层退出
         * 当跳出try看见有必须执行的finally块,就会跳进去执行块里的东西
         * 然后将finally块中的return后面计算的结果重新赋值给r
         * 结束程序,这样返回到的值就是为3
         * 
         * 
         * 其他的输出结果原因同上
         */
    }

    public static int test(String str){
        try{
            return str.charAt(0)-'0';
        }catch(NullPointerException e){
            return 1;
        }catch(Exception e){
            return 2;
        }finally{
            return 3;
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

Exception定义的方法



    public static void main(String[] args) {
        try{
            Person p=new Person();
            p.setAge(250);
            System.out.println("21");
        }catch(IllegalAgeException e){
            /*
             * Exception定义了方法:
             * void printStackTrace()
             * 该方法时用来将异常出现的代码执行过程完成输出,
             * 以便于程序员追踪并修改错误
             */
//          System.out.println("31");
            e.printStackTrace();
//          System.out.println("41");
            /*
             * String getMessage()
             * 得到出错信息
             */
            String message=e.getMessage();
            System.out.println("出错了!"+message);
        }
        System.out.println("11");
    }


 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

测试子类重写父类含有throws异常抛出的方法时多throws重写的规则

import java.awt.AWTException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;

/**
 * 测试子类重写父类含有throws异常抛出的方法时多throws重写的规则
 * @author Analyze
 *
 */
public class Father {
    public void dosome()throws IOException,AWTException{

}

}
class Son extends Father{
//可以不在抛出任何异常
// public void dosome(){}
//仅抛出父类方法中抛出的部分异常
// public void dosome()throws IOException{}
//抛出父类方法抛出异常的子类异常
// public void dosome()throws FileNotFoundException{}
//不可以抛出额外异常(与父类方法抛出异常没有继承关系的其他异常)
// public void dosome()throws SQLException{}
//不可以抛出父类方法抛出的异常的父类异常
// public void dosome()throws Exception{}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
其他还有很多异常,我就不一一列举了,我要说明的是,一个合格的程序员,需要对程序中常见的问题有相当的了解和相应的解决办法,否则仅仅停留在写程序而不会改程序的话,会极大影响到自己的开发的。关于异常的全部说明,在api里都可以查阅。 算术异常类:ArithmeticExecption 空指针异常类:NullPointerException 类型强制转换异常:ClassCastException 数组负下标异常:NegativeArrayException 数组下标越界异常:ArrayIndexOutOfBoundsException 违背安全原则异常:SecturityException 文件已结束异常:EOFException 文件未找到异常:FileNotFoundException 字符串转换为数字异常:NumberFormatException 操作数据库异常:SQLException 输入输出异常:IOException 方法未找到异常:NoSuchMethodException java.lang.AbstractMethodError 抽象方法错误。当应用试图调用抽象方法时抛出。 java.lang.AssertionError 断言错。用来指示一个断言失败的情况。 java.lang.ClassCircularityError 类循环依赖错误。在初始化一个类时,若检测到类之间循环依赖则抛出该异常java.lang.ClassFormatError 类格式错误。当Java虚拟机试图从一个文件中读取Java类,而检测到该文件的内容不符合类的有效格式时抛出。 java.lang.Error 错误。是所有错误的基类,用于标识严重的程序运行问题。这些问题通常描述一些不应被应用程序捕获的反常情况。 java.lang.ExceptionInInitializerError 初始化程序错误。当执行一个类的静态初始化程序的过程中,发生了异常时抛出。静态初始化程序是指直接包含于类中的static语句段。 java.lang.IllegalAccessError 违法访问错误。当一个应用试图访问、修改某个类的域(Field)或者调用其方法,但是又违反域或方法的可见性声明,则抛出该异常java.lang.IncompatibleClassChangeError 不兼容的类变化错误。当正在执行的方法所依赖的类定义发生了不兼容的改变时,抛出该异常。一般在修改了应用中的某些类的声明定义而没有对整个应用重新编译而直接运行的情况下,容易引发该错误。 java.lang.InstantiationError 实例化错误。当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常. java.lang.InternalError 内部错误。用于指示Java虚拟机发生了内部错误。 java.lang.LinkageError 链接错误。该错误及其所有子类指示某个类依赖于另外一些类,在该类编译之后,被依赖的类改变了其类定义而没有重新编译所有的类,进而引发错误的情况。 java.lang.NoClassDefFoundError 未找到类定义错误。当Java虚拟机或者类装载器试图实例化某个类,而找不到该类的定义时抛出该错误。 java.lang.NoSuchFieldError 域不存在错误。当应用试图访问或者修改某类的某个域,而该类的定义中没有该域的定义时抛出该错误。 java.lang.NoSuchMethodError 方法不存在错误。当应用试图调用某类的某个方法,而该类的定义中没有该方法的定义时抛出该错误。 java.lang.OutOfMemoryError 内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。 java.lang.StackOverflowError 堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出时抛出该错误。 java.lang.ThreadDeath 线程结束。当调用Thread类的stop方法时抛出该错误,用于指示线程结束。 java.lang.UnknownError 未知错误。用于指示Java虚拟机发生了未知严重错误的情况。 java.lang.UnsatisfiedLinkError 未满足的链接错误。当Java虚拟机未找到某个类的声明为native方法的本机语言定义时抛出。 java.lang.UnsupportedClassVersionError 不支持的类版本错误。当Java虚拟机试图从读取某个类文件,但是发现该文件的主、次版本号不被当前Java

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值