java异常小结

原创
2016/09/02 11:22
阅读数 211

一、java中异常的分类:

1.Error

当程序发生不可控的错误时,通常做法是通知用户并中止程序的执行。与异常不同的是Error及其子类的对象不应被抛出。

Error是throwable的子类,代表编译时间和系统错误,用于指示合理的应用程序不应该试图捕获的严重问题。

Error由Java虚拟机生成并抛出,包括动态链接失败,虚拟机错误等。程序对其不做处理。

2.Exception

Exception一般分为Checked异常和Runtime异常,所有RuntimeException类及其子类的实例被称为Runtime异常,不属于该范畴的异常则被称为CheckedException。

Checked异常(RuntimeException之外的其他异常)

只有java语言提供了Checked异常,Java认为Checked异常都是可以被处理的异常,所以Java程序必须显示处理Checked异常。如果程序没有处理Checked异常,该程序在编译时就会发生错误无法编译。这体现了Java的设计哲学:没有完善错误处理的代码根本没有机会被执行。对Checked异常处理方法有两种

1 当前方法知道如何处理该异常,则用try...catch块来处理该异常。
2 当前方法不知道如何处理,则在定义该方法是声明抛出该异常。

RuntimeException

Runtime如除数是0和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。

 

注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理

二、Java异常机制主要依赖于trycatchfinallythrowthrows五个关键字。

         1.try:它里面放置可能引发异常的代码

         2.catch:后面对应异常类型和一个代码块,用于表明该catch块用于处理这种类型的代码块,可以有多个catch块。

         3.finally:主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件),异常机制总是保证finally块总是被执行。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者   throw等终止方法的语句,则就不会跳回执行,直接停止。

         4.throw:用于抛出一个实际的异常,可以单独作为语句使用,抛出一个具体的异常对象。

         5.throws:用在方法签名中,用于声明该方法可能抛出的异常。

异常的处理

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

        抛出异常:当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。

        捕获异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。

        对于运行时异常、错误或可查异常,Java技术所要求的异常处理方式有所不同。

        由于运行时异常的不可查性,为了更合理、更容易地实现应用程序,Java规定,运行时异常将由Java运行时系统自动抛出,允许应用程序忽略运行时异常。

       对于方法运行中可能出现的Error,当运行方法不欲捕捉时,Java允许该方法不做任何抛出声明。因为,大多数Error异常属于永远不能被允许发生的状况,也属于合理的应用程序不该捕捉的异常。

       对于所有的可查异常,Java规定:一个方法必须捕捉,或者声明抛出方法之外。也就是说,当一个方法选择不捕捉可查异常时,它必须声明将抛出异常。

        能够捕捉异常的方法,需要提供相符类型的异常处理器。所捕捉的异常,可能是由于自身语句所引发并抛出的异常,也可能是由某个调用的方法或者Java运行时 系统等抛出的异常。也就是说,一个方法所能捕捉的异常,一定是Java代码在某处所抛出的异常。简单地说,异常总是先被抛出,后被捕捉的。

         任何Java代码都可以抛出异常,如:自己编写的代码、来自Java开发环境包中代码,或者Java运行时系统。无论是谁,都可以通过Java的throw语句抛出异常。

        从方法中抛出的任何异常都必须使用throws子句。

        捕捉异常通过try-catch语句或者try-catch-finally语句实现。

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

三、常见的异常

1. runtimeException子类:

    1、 java.lang.ArrayIndexOutOfBoundsException
    数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
    2、java.lang.ArithmeticException
    算术条件异常。譬如:整数除零等。
    3、java.lang.NullPointerException
    空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等
    4、java.lang.ClassNotFoundException

    找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。

    5、java.lang.NegativeArraySizeException  数组长度为负异常

    6、java.lang.ArrayStoreException 数组中包含不兼容的值抛出的异常

    7、java.lang.SecurityException 安全性异常

    8、java.lang.IllegalArgumentException 非法参数异常

2.IOException

 IOException:操作输入流和输出流时可能出现的异常。

 EOFException   文件已结束异常

 FileNotFoundException   文件未找到异常

3. 其他

 ClassCastException    类型转换异常类

 ArrayStoreException  数组中包含不兼容的值抛出的异常

 SQLException   操作数据库异常类

 NoSuchFieldException   字段未找到异常

 NoSuchMethodException   方法未找到抛出的异常

 NumberFormatException    字符串转换为数字抛出的异常

 StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常

 IllegalAccessException  不允许访问某类异常

 InstantiationException  当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常。

4. 用户自定义的异常

  用户自定义异常类,只需继承Exception类即可,然后通过throw关键字抛出异常。

举例实验:

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            return t;

        } catch (Exception e) {

            // result = "catch";

            t = "catch";

            return t;

        } finally {

            t = "finally";

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

 首先程序执行try语句块,把变量t赋值为try,由于没有发现异常,接下来执行finally语句块,把变量t赋值为finally,然后return t,则t的值是finally,最后t的值就是finally,程序结果应该显示finally,但是实际结果为try。在try语句的return块中,return 返回的引用变量(t 是引用类型)并不是try语句外定义的引用变量t,而是系统重新定义了一个局部引用t’,这个引用指向了引用t对应的值,也就是try ,即使在finally语句中把引用t指向了值finally,因为return的返回引用已经不是t ,所以引用t的对应的值和try语句中的返回值无关了。

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            return t;

        } catch (Exception e) {

            // result = "catch";

            t = "catch";

            return t;

        } finally {

            t = "finally";

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

我们发现try语句中的return语句给忽略。可能jvm认为一个方法里面有两个return语句并没有太大的意义,所以try中的return语句给忽略了,直接起作用的是finally中的return语句,所以这次返回的是finally。

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (Exception e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

            // System.out.println(t);

            // return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这里面try语句里面会抛出 java.lang.NumberFormatException,所以程序会先执行catch语句中的逻辑,t赋值为catch,在执行return之前,会把返回值保存到一个临时变量里面t ',执行finally的逻辑,t赋值为finally,但是返回值和t',所以变量t的值和返回值已经没有关系了,返回的是catch

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (Exception e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个和例2有点类似,由于try语句里面抛出异常,程序转入catch语句块,catch语句在执行return语句之前执行finally,而finally语句有return,则直接执行finally的语句值,返回finally

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (Exception e) {

            t = "catch";

            Integer.parseInt(null);

            return t;

        } finally {

            t = "finally";

            //return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个例子在catch语句块添加了Integer.parser(null)语句,强制抛出了一个异常。然后finally语句块里面没有return语句。继续分析一下,由于try语句抛出异常,程序进入catch语句块,catch语句块又抛出一个异常,说明catch语句要退出,则执行finally语句块,对t进行赋值。然后catch语句块里面抛出异常。结果是抛出java.lang.NumberFormatException异常

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (Exception e) {

            t = "catch";

            Integer.parseInt(null);

            return t;

        } finally {

            t = "finally";

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个例子和上面例子中唯一不同的是,这个例子里面finally 语句里面有return语句块。try catch中运行的逻辑和上面例子一样,当catch语句块里面抛出异常之后,进入finally语句快,然后返回t。则程序忽略catch语句块里面抛出的异常信息,直接返回t对应的值 也就是finally。方法不会抛出异常

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (NullPointerException e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个例子里面catch语句里面catch的是NPE异常,而不是java.lang.NumberFormatException异常,所以不会进入catch语句块,直接进入finally语句块,finally对s赋值之后,由try语句抛出java.lang.NumberFormatException异常。

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

 

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (NullPointerException e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

和上面的例子中try catch的逻辑相同,try语句执行完成执行finally语句,finally赋值s 并且返回s ,最后程序结果返回finally

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";return t;

        } catch (Exception e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

            String.valueOf(null);

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个例子中,对finally语句中添加了String.valueOf(null), 强制抛出NPE异常。首先程序执行try语句,在返回执行,执行finally语句块,finally语句抛出NPE异常,整个结果返回NPE异常。

下面看一个例子(例1),来讲解java里面中try、catch、finally的处理流程

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            return t;

        } catch (Exception e) {

            // result = "catch";

            t = "catch";

            return t;

        } finally {

            t = "finally";

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

  首先程序执行try语句块,把变量t赋值为try,由于没有发现异常,接下来执行finally语句块,把变量t赋值为finally,然后return t,则t的值是finally,最后t的值就是finally,程序结果应该显示finally,但是实际结果为try。通过字节码,我们发现,在try语句的return块中,return 返回的引用变量(t 是引用类型)并不是try语句外定义的引用变量t,而是系统重新定义了一个局部引用t’,这个引用指向了引用t对应的值,也就是try ,即使在finally语句中把引用t指向了值finally,因为return的返回引用已经不是t ,所以引用t的对应的值和try语句中的返回值无关了。

下面在看一个例子:(例2)

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            return t;

        } catch (Exception e) {

            // result = "catch";

            t = "catch";

            return t;

        } finally {

            t = "finally";

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这里稍微修改了 第一段代码,只是在finally语句块里面加入了 一个 return t 的表达式。

按照第一段代码的解释,先进行try{}语句,然后在return之前把当前的t的值try保存到一个变量t',然后执行finally语句块,修改了变量t的值,在返回变量t。

这里面有两个return语句,但是程序到底返回的是try 还是 finally。

我们发现try语句中的return语句给忽略。可能jvm认为一个方法里面有两个return语句并没有太大的意义,所以try中的return语句给忽略了,直接起作用的是finally中的return语句,所以这次返回的是finally。

接下来在看看复杂一点的例子:(例3)

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

 

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (Exception e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

            // System.out.println(t);

            // return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这里面try语句里面会抛出 java.lang.NumberFormatException,所以程序会先执行catch语句中的逻辑,t赋值为catch,在执行return之前,会把返回值保存到一个临时变量里面t ',执行finally的逻辑,t赋值为finally,但是返回值和t',所以变量t的值和返回值已经没有关系了,返回的是catch

例4:

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (Exception e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个和例2有点类似,由于try语句里面抛出异常,程序转入catch语句块,catch语句在执行return语句之前执行finally,而finally语句有return,则直接执行finally的语句值,返回finally

例5:

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (Exception e) {

            t = "catch";

            Integer.parseInt(null);

            return t;

        } finally {

            t = "finally";

            //return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个例子在catch语句块添加了Integer.parser(null)语句,强制抛出了一个异常。然后finally语句块里面没有return语句。继续分析一下,由于try语句抛出异常,程序进入catch语句块,catch语句块又抛出一个异常,说明catch语句要退出,则执行finally语句块,对t进行赋值。然后catch语句块里面抛出异常。结果是抛出java.lang.NumberFormatException异常

例子6:

public class TryCatchFinally {

 

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (Exception e) {

            t = "catch";

            Integer.parseInt(null);

            return t;

        } finally {

            t = "finally";

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个例子和上面例子中唯一不同的是,这个例子里面finally 语句里面有return语句块。try catch中运行的逻辑和上面例子一样,当catch语句块里面抛出异常之后,进入finally语句快,然后返回t。则程序忽略catch语句块里面抛出的异常信息,直接返回t对应的值 也就是finally。方法不会抛出异常

例子7:

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (NullPointerException e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个例子里面catch语句里面catch的是NPE异常,而不是java.lang.NumberFormatException异常,所以不会进入catch语句块,直接进入finally语句块,finally对s赋值之后,由try语句抛出java.lang.NumberFormatException异常。

例子8

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";

            Integer.parseInt(null);

            return t;

        } catch (NullPointerException e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

和上面的例子中try catch的逻辑相同,try语句执行完成执行finally语句,finally赋值s 并且返回s ,最后程序结果返回finally

例子9:

public class TryCatchFinally {

    @SuppressWarnings("finally")

    public static final String test() {

        String t = "";

        try {

            t = "try";return t;

        } catch (Exception e) {

            t = "catch";

            return t;

        } finally {

            t = "finally";

            String.valueOf(null);

            return t;

        }

    }

    public static void main(String[] args) {

        System.out.print(TryCatchFinally.test());

    }

}

这个例子中,对finally语句中添加了String.valueOf(null), 强制抛出NPE异常。首先程序执行try语句,在返回执行,执行finally语句块,finally语句抛出NPE异常,整个结果返回NPE异常。

对以上所有的例子进行总结

1 try、catch、finally语句中,在如果try语句有return语句,则返回的之后当前try中变量此时对应的值,此后对变量做任何的修改,都不影响try中return的返回值

2 如果finally块中有return 语句,则返回try或catch中的返回语句忽略。

3 如果finally块中抛出异常,则整个try、catch、finally块中抛出异常

4.无论try、catch、finally 中遇到throw抛出异常或者return都是代表程序到此终止执行,之外的代码将不会被继续执行。

5.异常都是先要抛出然后捕获异常。

6.抛出的异常和catch的异常类型要匹配才能捕获,否则往上抛出直至jvm捕获抛出。

7.finally中没有return和throw或者其他异常抛出时候,才会返回到try或者catch里继续执行。

所以使用try、catch、finally语句块中需要注意的是

1 尽量在try或者catch中使用return语句。通过finally块中达到对try或者catch返回值修改是不可行的。

2 finally块中避免使用return语句,因为finally块中如果使用return语句,会显示的消化掉try、catch块中的异常信息,屏蔽了错误的发生

3 finally块中避免再次抛出异常,否则整个包含try语句块的方法回抛出异常,并且会消化掉try、catch块中的异常

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部