Skip to content
sqmax edited this page May 13, 2018 · 1 revision

异常

标签(空格分隔): javaSE复习


异常类的继承体系

![]

Java把所有的非正常情况分为两类:异常(Exception)和错误(Error),它们都继承自Throwable父类。

Error

Error一般指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等。这类错误无法恢复或不可捕获,将导致应用程序中断。通常程序无法处理这些错误,因此应用程序不应该使用try来捕获Error对象。 在默认设置下,一般java程序启动的时候,最大可以使用16m的内存 如例不停的给StringBuffer追加字符,很快就把内存使用光,抛出OutOfMemoryError。下面故意使程序发生这种错误。

public class ErrorTest {
    public static void main(String[] args) {
        StringBuffer sb=new StringBuffer();
        for (int i=0;i<Integer.MAX_VALUE;i++) {
            sb.append('a');
        }
    }
}

运行结果如下:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3332)
	at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:649)
	at java.lang.StringBuffer.append(StringBuffer.java:381)
	at top.sqmax.chapter10.ErrorTest.main(ErrorTest.java:13)

我们也可以用try catch捕获错误

public class ErrorTest {
    public static void main(String[] args) {
        StringBuffer sb=new StringBuffer();
        try {
            for (int i = 0; i < Integer.MAX_VALUE; i++) {
                sb.append('a');
            }
        } catch (Error error) {
            System.out.println("捕获到错误:"+error);
        }
    }
}

运行结果如下:

捕获到错误:java.lang.OutOfMemoryError: Java heap space

Exception

包括Checked异常和Runtime异常。 区别:

  • CheckedException必须被处理,要么try catch,要么往外抛,给调用者处理。如果不处理,编译不通过。
  • RuntimeException,不必用try catch处理。常见的运行时异常有:
    • 除数不能为0异常:ArithmeticException
    • 下标越界异常:ArrayIndexOutOfBoundsException
    • 空指针异常:NullPointerException 在编写代码的时候,依然可以使用try catch throws进行处理。Java之所以会设计运行时异常的原因之一,是因为下标越界,空指针这些运行时异常太过于普遍,如果都需要进行捕捉,代码的可读性就会变得很糟糕。

finally回收资源

如果try块的某条语句发生了异常,该语句后的其他语句通常不会得到执行的机会,这将导致位于该语句后的资源回收语句得不到执行。如果放在catch块里也不行,也可能得不到执行。 为了保证一定能回收try块打开的物理资源,异常处理机制提供了finally块 异常处理try块必需,catch块和finally至少出现一个。

try里有return语句 通常,一旦方法执行到return语句的地方,该程序就会立即结束该方法;现在不会了,在return语句结束方法之前,一定会先执行finally块里的代码

    public static void main(String[] args) {
        FileInputStream fis=null;
        try {
            fis=new FileInputStream("a.txt");
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
//            强制方法返回
            return;
//            System.exit(0);
        }finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("执行finally块里的资源回收!");
        }
    }
}

运行结果如下:

a.txt (系统找不到指定的文件。)
执行finally块里的资源回收

但是如果强制退出虚拟机(System.exit(0);),就不会再执行finally语句块里的代码。

Java7的自动关闭资源的try语句

try关键字后紧跟一对圆括号,来声明、初始化一个或多个资源(此处资源是指那些必须在程序结束时显示关闭的资源,比如数据库连接,文件关闭),try语句在结束时会自动关闭这些资源。 注意:这些资源必须实现AutoCloseable或Closeable接口。

public class AutoCloseTest {
    public static void main(String[] args) {
        try (
            BufferedReader br =new BufferedReader(new FileReader("AutoCloseTest.java"));
            PrintStream ps=new PrintStream(new FileOutputStream("a.txt"));
            )
        {
            System.out.println(br.readLine());
            ps.println("hello");
        }
        catch (Exception  e) {
            e.printStackTrace();
        }
    }
}

使用throws声明抛出异常

使用throw生命抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该有上一级调用者处理;如果main方法也不知道该如何处理这种异常,也可以使用throws声明抛出异常,该异常将交给JVM处理。JVM处理异常的方式是,打印异常的跟踪栈信息,并终止程序。 throws用在方法声明上,使用throws声明抛出异常有一下两点限制:

  • 重写时子类方法声明抛出的异常类型应该是父类方法声明抛出异常的子类或相同。
  • 子类方法声明抛出的异常不允许比父类方法声明抛出的异常多。

使用throw抛出异常

throw开发者自行抛出的异常,出现在方法体内,执行抛出的异常也可以用try catch捕获,也可以抛出,让方法的调用者处理。

自定义异常

用户自定义异常都应该继承Exception基类,如果希望自定义RuntimeException异常,则应该继承RuntimeException基类。

异常链

在Java1.4后,所有的Throwable子类在构造器中都可以接收一个caulse对象作为参数。这个cause就用来表示原始异常,这样就可以吧原始异常传递给新的异常,如自定义异常,使得即使在当前位置创建并抛出新的异常,也能够通过异常链追踪到异常最初发生的位置。

以后补充。。。。。

Clone this wiki locally