Java日记(9)— 异常机制

1概念:

java提供了异常处理机制来处理程序中运行的错误(如除数为0,数组下标越界,文件不能打开,内存不够用等)
按照这种机制,将程序运行中打断正常程序流程的任何不正常的情况成为错误(Error)或异常(Exception)。
java系统中,专门设置了一个调用栈,此栈中装有指向异常处理的指针。在程序运行时,系统会把收集到的异常和异常处理指针所指向的处理类型逐个比较:如果找到相符的类型,则转向相应的方法处理;如果没有找到相符的类型指针,则终止程序运行,并显示解释信息。

在java中,异常(Exception)一般由两种原因造成:
(1).程序存在非法操作(如除0),这种异常经常是程序员出于无意或考虑不周造成的,所以称为<b>隐式异常</b>
(2).程序员在程序中使用了throw语句引起的异常,这种异常是程序员出于某种考虑有意安排的,所以成为显示异常。

2.Java异常类:

java所有的异常都是以类的形式存在的,除了预定义的异常外,程序员可也以自定义异常.

抛出异常:如果在一个方法的运行过程中发生了异常(隐式或显式),则这个方法会自动生产一个异常类对象,该异常类对象将被提交给java运行时的系统,这个过程称为抛出异常
捕获异常:当java运行时系统收到异常对象,会查找能处理这一异常的代码并把当前异常的对象交给其处理,这个过程称为捕获异常

2.1预定义的异常类:

Javal类库内的各个包里面定义了很多异常类,所有的异常类都直接或间接的继承了Throwable类:

这里写图片描述



Throwable常用的构造方法和方法(都很重要)

  • public Exception():构造详细信息为null的新异常
  • public Exception(String message):构造详细信息为message的新异常
  • public String getMessage():返回异常抛出原因的字符串
  • public String toString():返回异常的简短描述,包括异常类名,异常原因
  • public void printStackTrace():输出调用堆栈的跟踪信息(注意理解”跟踪“,对比 System.out.println(异常类的类名),看看有什么区别)



下面介绍Throwable的两个子类:Error和Exception

2.1.1 Error类

    是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。

     这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。 

2.2Exception类

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

   通常,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。

  可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。


 不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。


   运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。


   非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

2.2自定义的异常类:

(1)自定义的异常类一般都是以Exception类为父类
(2)自定义的一场类对象只能用throw语句抛出

代码:

package Example_7;
import java.util.Scanner;
public class Example_7_8 {

    public static void main(String[] args) {
        final int MAX = 25,MIN=10;
        Scanner scn = new Scanner(System.in);
        OutOfRangException e = new OutOfRangException();
        System.out.println("输入从"+MIN+"到"+MAX+"的整数");
        try{
            int value = scn.nextInt();
            if(value<MIN || value >MAX)
                throw e;                            //抛出自定义异常
        }catch(OutOfRangException e1){
            System.out.println(e1.toString());
        }
        System.out.println("main结束");
    }

}


//自定义异常类:OutOfRangException
class OutOfRangException extends Exception{         //通过指定其父类是Exception,从而知道该子类是个异常类
    OutOfRangException(){
        super("输入数据超出范围");                      //调用父类Exception的Exception(String)方法。
    }
}

3.异常处理:

异常处理指在程序发生异常时,捕获异常并进行处理或抛弃异常,使程序继续运行。
java中关于异常处理有5个关键字:try,catch,finally,throw,throws

3.1 try-catch-finally语句:

规则:

1) 必须在 try 之后添加 catch 或 finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。

2) 必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。

3) catch 块与相应的异常类的类型相关。

4) 一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。即Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或其子类的实例,就执行这个catch代码块,不会再执行其他的 catch代码块

5) 可嵌套 try-catch-finally 结构。

6) 在 try-catch-finally 结构中,可重新抛出异常。

7) 除了下列情况,总将执行 finally 做为结束:JVM 过早终止(调用 System.exit(int));在 finally 块中抛出一个未处理的异常;计算机断电。或遭遇到病毒攻击。

执行顺序:

1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;

2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;

3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;

这里写图片描述

注意:

1):若try中有return语句时,当执行到return时,会自动先执行finally语句
2):多个catch语句时,应该先把参数为异常子类的放在前面,把父类放在后面;否则的话永远都执行不到参数为异常子类的catch,编译器报错。
3):finally中尽量不要使用return,这一种很不好的编程风格,它会覆盖掉所有的其它返回,并且吃掉catch中抛出的异常。

代码(try-catch-finally语句示例):

import javax.print.attribute.standard.PrinterLocation;

public class Example_7_3 {

    public static void main(String[] args) {
        int a,b,c;
        a = 110;
        b = 10;
        try{
            c = a/b;
            System.out.println(a+"/"+b+"="+c);
        }catch(ArithmeticException e){
            System.out.println("出现被0除的异常情况");
        }catch(Exception e){
            System.out.println("异常类型为"+e);
        }finally{
            System.out.println("除数="+a);
            System.out.println("被除数="+b);
        }
    }

}

3.2 throw和throws:

使用throw实现显式异常:
语法格式:
    第一种: throw new ExceptionType(...);//ExceptionType为Throwable的子类
    第二种:ExceptionType e = new Exception(...);
           throw e;

程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。

throws:

如果抛出了检查异常,则还应该在方法头部声明方法可能抛出的异常类型(throws ExceptionType)。该方法的调用者也必须检查处理抛出的异常。

如果所有方法都层层上抛获取的异常,最终JVM会进行处理,处理也很简单,就是打印异常消息和堆栈信息。如果抛出的是Error或RuntimeException,则该方法的调用者可选择处理该异常

代码:

import java.io.*;
public class Example_7_5 {

    public static void main(String[] args) {
        int a=0;
        try{
            a=calc(1);
            System.out.println("a="+a);
        }catch(ArithmeticException e){
            System.out.println("调用calc时发生了异常"+e.getMessage());
            e.printStackTrace();
            //System.out.println(e);        //注意着两种的区别
        }
    }

    public static int calc(int x){
        int z=0;
        z =110/x;
        return z;
    }
}

还有一个需要思考的代码(throws):

package Example_7;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Example_7_7 {

    public static void main(String[] args)throws Exception{  //A行
        System.out.println("输入一行文本");
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader inputReader = new BufferedReader(isr);
        String inputLine = inputReader.readLine();          //若A行不写throws 则该行报错,因为readLine()显式抛出异常,调用该方法的函数必须处理他,当然也可以用try-catch-finally语句
        System.out.println("输入的文本是:"+inputLine);

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值