Java学习系列文章第五篇:说说Java中的异常

在正常的程序设计中,程序异常处理是非常关键和重要的一部分。试想一个项目中没有一个好的异常处理,这个项目会怎么样?

什么是异常

异常其实是程序上的错误,包括程序逻辑错误和系统错误。比如数组下标越界、内存溢出等,这些都是意外的情况,错误在我们的程序的编写过程中会经常发生,包括编译期间和运行期间的错误。在编译期间出现的错误编译器会帮助我们修正,可是在运行期间的错误编译器就无能为力了,并且运行期间的错误往往是难以预料的。

程序出现了错误,我们不能不去处理,这样的程序的健壮性太差了。为了提高程序的健壮性我们要合理的解决这些错误!于是Java中提供了异常的处理机制,通过异常来处理程序运行期间中出现的错误。通过这一特性,我们可以很好的提高程序的健壮性。

Java是一个全面的面向对象语言,不像PHP那样,既支持过程式编程,也支持面向对象编程。Java中异常的父类是java.lang.Throwable类。在Java中定义很多的的异常类,比如OutOfMenoryError、NullPointerException、IndexOutOfBoundsException等。

Exception 类的层次

所有的异常类是从 java.lang.Exception 类继承的子类。

  • Exception 类是 Throwable类的子类。除了Exception类外,Throwable还有一个子类Error 。
    Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
  • Error 用来指示运行时环境发生的错误。
    例如,JVM 内存溢出。一般地,程序不会从错误中恢复。
    异常类有两个主要的子类:IOException 类和 RuntimeException 类。

Exception,也就是我们经常见到的一些异常情况,例如NullPointerException、IndexOutOfBoundsException等,这些异常时是我们可以处理的异常。

Exception类的异常包括checked exception和unchecked exception(unchecked exception也称作运行时异常RuntimeException,Exception类的异常都是在运行期间发生的),对于运行时异常,Java编译器不要求必须进行异常处理捕获处理或者抛出,这个由程序员自行决定。

checked exception(检查异常),也称为非运行时异常(运行时异常以外的异常就是非运行时异常),Java编译器强制程序员必须捕获处理,比如常见的IOException和SQLException。对于非运行时异常如果不进行捕获或者抛出处理,Java编译器都不会通过。

在网上找了一个图,能够很清楚的描述在Java中,异常类的结构层次(有些时候语言就略显苍白,不如图片或者视频表现力丰富)。

image
在Java中,所有的异常都是继承至java.lang.Throwable类。Error类是error类型异常的父类,Exception类是exception类型异常的父类,RuntimeException类是所有运行时异常的父类,RuntimeException以外的并且继承Exception的类是非运行时异常。

  • 典型的RuntimeException包括NullPointerException、IndexOutOfBoundsException、IllegalArgumentException等。

  • 典型的非RuntimeException包括IOException、SQLException等。

Java如何处理异常

在Java中如果需要处理异常,必须先对异常进行捕获(这一点是和PHP是相同的)。使用try和catch关键字进行处理。具体的规则如下:

1
2
3
4
5
6
7
8
9
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}finally{
// 程序代码
}

来段实际的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.io.*;
public class ExcepTest{

public static void main(String args[]){
try {
File file = new File("/Users/sam/a.txt");
if(!file.exists())
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}

被try块包围的代码说明这段代码可能会发生异常,一旦发生异常,异常便会被catch捕获到,然后需要在catch块中进行异常处理。这是一种处理异常的方式。在Java中还提供了另一种异常处理方式即抛出异常,顾名思义,也就是说一旦发生异常,我把这个异常抛出去,让调用者去进行处理,自己不进行具体的处理,此时需要用到throw和throws关键字。

我们看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main {
public static void main(String[] args) {
try {
createFile();
} catch (Exception e) {
// TODO: handle exception
}
}

public static void createFile() throws IOException{
File file = new File("/Users/sam/a.txt);
if(!file.exists())
file.createNewFile();
}
}

这段代码和上面一段代码的区别是,在实际的createFile方法中并没有捕获异常,而是用throws关键字声明抛出异常,即告知调用者此方法可能会抛出IOException,需要调用者进行捕获处理。那么在main方法中调用createFile方法的时候,采用try…catch块进行了异常捕获处理。

还可以使用throw关键字进行抛出异常。看下面的例子:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package exception;

/**
* Created by Sam on 18/6/17.
*/
public class Main {

public static void main(String[] args){
People people = new People("Sam",new Byte("25"));
people.sayAge();
}
}


class People {

private String name;
private Byte age;

public People(String name, Byte age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Byte getAge() {
return age;
}

public void setAge(Byte age) {
this.age = age;
}

public Byte sayAge(){
if (age > Byte.MIN_VALUE){
throw new MyException("年龄太大了","100" );
}
return age;
}
}


public class MyException extends RuntimeException {

private String code;

public MyException(String message, String code) {
super(message);
this.code = code;
}

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}
}

上面就是利用throw关键字进行手动抛出异常。调用者可以捕获处理异常,也可以不用处理异常。下面我们就修改一下代码进行捕获处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Main {

public static void main(String[] args){
People people = new People("Sam",new Byte("25"));
try {
people.sayAge();
}catch (Exception e){
System.out.println(e);
}

}
}
程序输出:
exception.MyException: 年龄太大了

也就说在Java中进行异常处理的话,对于可能会发生异常的代码,可以选择三种方法来进行异常处理:

1、对代码块用try..catch进行异常捕获处理;

2、在该代码的方法体外用throws进行抛出声明,告知此方法的调用者这段代码可能会出现这些异常,你需要谨慎处理。此时有两种情况:

如果声明抛出的异常是非运行时异常,此方法的调用者必须显示地用try..catch块进行捕获或者继续向上层抛出异常。

如果声明抛出的异常是运行时异常,此方法的调用者可以选择地进行异常捕获处理。

3、在代码块用throw手动抛出一个异常对象,此时也有两种情况,跟2)中的类似:

如果抛出的异常对象是非运行时异常,此方法的调用者必须显示地用try..catch块进行捕获或者继续向上层抛出异常。

如果抛出的异常对象是运行时异常,此方法的调用者可以选择地进行异常捕获处理。(如果最终将异常抛给main方法,则相当于交给jvm自动处理,此时jvm会简单地打印异常信息)

关于Java的异常机制就暂时说到这里。

  • 作者: Sam
  • 发布时间: 2018-06-29 22:00:54
  • 最后更新: 2019-12-09 23:03:26
  • 文章链接: https://ydstudios.gitee.io/post/4b7e7a69.html
  • 版权声明: 本网所有文章除特别声明外, 禁止未经授权转载,违者依法追究相关法律责任!