Java入门7---异常处理

一、Java中异常的分类

当执行一个程序时,如果发现异常,则异常之后的代码就不再执行。

1.Error

Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。一般不编写针对性的代码进行处理。

2.Exception

其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:

  1. 空指针访问
  2. 试图读取不存在的文件
  3. 网络连接中断

2.1 编译时异常

在编译期间会出现的异常(执行javac.exe命令时,出现异常)

2.2 运行时异常

在运行期间出现的异常(执行java.exe命令时,出现异常)

  出现运行时异常后,系统会把异常一直往上层抛出,直到遇到处理代码为止。若没有处理块,则抛到最上层;如果是多线程就用Thread.run()方法抛出,如果是单线程,就用main()方法抛出。抛出之后,如果是线程,那么这个线程也就退出了。如果是主程序抛出的异常,那么整个程序也就退出了。所以,如果不对异常进行处理,后果是非常严重的,一旦发生,要么是线程中止,要么是主程序终止。

二、异常处理

  1. 对于运行时异常,可以不显示的进行处理
  2. 对于编译时异常,必须要显示的进行处理

1.如何处理Exception异常

  1. 上游:手动抛/自动抛
  2. 下游:try-catch-finally/throws

上下游各有两种方法,可以自由搭配。

抓抛模型:

  1. “抓”:抓住上一步抛出来的异常类的对象。如何抓?即为异常处理的方式。
  2. “抛”:一旦抛出此异常类的对象,那么程序就终止执行,此异常类的对象抛给方法的调用者。

1.1 抓

1. try-catch-finally

try{
  // 可能出现异常的代码  
}catch(Exception e1){
 // 处理的方式1
}catch(Exception e2){
  // 处理的方式2
}finally{
  // 一定要执行的代码
}

注意:

  1. try内声明的变量,类似于局部变量,出了try{}语句,就不能被调用
  2. finally是可选的
  3. catch语句内部是对异常对象的处理
  4. 可以有多个catch语句,try中抛出的异常类对象从上往下去匹配catch中的异常类的类型,一旦满足就执行catch的代码。执行完,就跳出其后的多条catch语句。
  5. 如果异常处理了,那么其后的代码继续执行。
  6. 如果catch中多个异常类型是“并列”关系,谁上谁下都可以;如果catch中多个异常类型是“包含”关系,须将子类放在父类的上面,进行处理,否则报错!
  7. finally中存放的是一定会被执行的代码,不管try中、catch中是否仍有异常未被处理,以及是否有return语句。
  8. try-catch是可以嵌套的。  

举例1:

没有异常 有异常

有finally时,先执行finally里面语句,再报异常。

举例2:面试题

2. 在方法的声明处显示的抛出该异常对象的类型 throws

  如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理

如:

public void readFile(String File) thorws FileNotFoundException {
  ...
  // 读文件的操作可能产生FileNotFoundException类型的异常
  FileInputStream fis = new FileInputStream(file);
  ......  
}

当在此方法内部出现异常的时候,会抛出一个异常类的对象,抛给方法的调用者。

异常的对象可以逐层向上抛,直至main中。当然在向上抛的过程中,可以再通过try...catch...finally进行处理。

1.2 抛

1. 自动抛出

2. 手动抛出

  1. 方法的声明处,显示的抛出该异常对象的类型,抛给方法的调用者 ;
  2. 异常的对象可以逐层向上抛,直至mian中;
  3. 当然在向上抛的过程中,可以再通过try-catch-finally进行处理。
  1. 抛出的异常类型,若是RuntimeException,可以不显示的处理;
  2. 若是一个Exception,必须要显示的处理。

 抛异常,不处理(throw是回避问题的方式)

抛异常,处理(try-catch是真正解决问题的方式)

手动抛出的异常类对象(throw new Exception("异常")),既可以是现成的异常类,也可以是自己创建的异常类。

3. 自定义异常类

方法:

  1. 继承现有的异常类;
  2. 提供一个序列号,提供几个重载的构造器。

举例1:

 

举例2:

举例3:

/**
 * 功能描述:自定义异常
 * @since 2020-08-09
 */
public class EcmDef {
    public static int ecm(int a, int b) throws EcmException{ // throws抓异常,捕获给调用该方法的地方,即EcmDef.ecm(num1,num2)
        if ( a < 0 || b < 0 ) {
            throw new EcmException("不能有负数"); // throw抛异常
        }
        int res = a / b;
        return res;
    }
    public static void main(String[] args) {
        try {
            int num1 = Integer.parseInt(args[0]);
            int num2 = Integer.parseInt(args[1]);
            EcmDef.ecm(num1,num2); // 要处理异常
        } catch (NumberFormatException e) {
            System.out.printf("数据类型不一致");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.printf("缺少命令行参数");
        } catch (ArithmeticException e) {
            System.out.printf("被除数不能为0");
        } catch (EcmException e) { // 处理throws抓到的异常
            System.out.printf(e.getMessage());
        }
    }
}

// 自定义异常类
class EcmException extends Exception {

    static final long serialVersionUID = -3386993124229549L;

    public EcmException() { }

    public EcmException(String msg) {
        super(msg);
    }
}

  

4. 抛异常的方法的重写规则

  子类重写父类的方法,其抛出的异常类型只能是被重写的方法的异常类的子类异常类型一样

  因为如果子类抛出的异常比父类的还大,则在编译的时候不会报错,因为编译时候默认还是会catch父类抛出的异常,但是在方法的执行过程中,还是会执行子类的异常,如果抛出的异常大,catch方法会失效,说明程序的设计是有一定问题的。

原文地址:https://www.cnblogs.com/nxf-rabbit75/p/13443751.html