小东吖 之 java 常见的异常处理

一.异常处理的概念

异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。

比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出java.lang.ArithmeticException的异常。

异常发生的原因有很多,通常包含以下几大类:

用户输入了非法数据。
要打开的文件不存在。
网络通信时连接中断,或者JVM内存溢出。

这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。-

要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:

检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

异常指不期而至的各种状况,如:文件找不到、网络连接失败、除0操作、非法参数等。异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程。

Java语言在设计的当初就考虑到这些问题,提出异常处理的框架的方案,所有的异常都可以用一个异常类来表示,不同类型的异常对应不同的子类异常(目前我们所说的异常包括错误概念),定义异常处理的规范,在JDK1.4版本以后增加了异常链机制,从而便于跟踪异常。

Java异常是一个描述在代码段中发生异常的对象,当发生异常情况时,一个代表该异常的对象被创建并且在导致该异常的方法中被抛出,而该方法可以选择自己处理异常或者传递该异常。

二.常见到的异常

Throwable 异常处理的父类
Error 系统崩溃 数据库崩溃 (可以说和我们的代码没有关系)
Exception 异常 (是跟我们代码有关系的)
RuntimeException 运行时异常
常见的异常

// 空指针异常
// 角标异常
// 算数异常

int[] array = {1,3,5,7};
// 这时候就是角标越界
System.out.println(array[5]);
array = null;// array 指向一个空内存
// 这个时候就是空指针异常(访问一块不属于你的内存区域)
System.out.println(array[0]);
// 算数异常 也就是说不符合算数规则
System.out.println(11 / 0);

2.出现异常 系统如何进行处理?
a).main函数自己解决
b).报问题给上级去解决 (这里谁调用main函数 谁去解决)
交给JVM虚拟机去解决 然后JVM给你报错 打印错误信息 错误发生在什么类的什么位置

三.异常处理

Java异常处理涉及到五个关键字,分别是:try、catch、finally、throw、throws。下面将骤一介绍,通过认识这五个关键字,掌握基本异常处理知识。

  • try – 用于监听。将要被监听的代码(可能抛出异常的代码)放在try语句块之内,当try语句块内发生异常时,异常就被抛出。
  • catch – 用于捕获异常。catch用来捕获try语句块中发生的异常。
  • finally – finally语句块总是会被执行。它主要用于回收在try块里打开的物力资源(如数据库连接、网络连接和磁盘文件)。只有finally块,执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。
  • throw – 用于抛出异常。
  • throws – 用在方法签名中,用于声明该方法可能抛出的异常。
1.捕获异常的流程
1.发生异常
2.根据发生的异常 产生对应的异常对象
3.这个异常对象会返回给调用者
4.如果调用者处理了这个异常(try – catch) 异常对象会跟catch进行匹配 匹配上 执行catch中的语句 程序会继续执行
5.如果这个调用者没有处理这个异常 默认交给JVM去处理 根据产生异常 打印对应的错误信息 程序停止

1.举个算数异常的例子

// 测试异常
// 举个算数异常的例子
TestException test = new TestException();
    try {
        //可能发生异常的代码 要检测的代码
        int number = test.fun(10, 0);
        // 这块返回了异常对象
        // new ArithmeticException ("/ by zero")
        System.out.println(number);

    } catch (ArithmeticException e) {
        // 捕获异常 该怎么办
        // catch 如何就能捕获异常?

        // ArithmeticException e = new ArithmeticException ("/ by zero")
        // catch会匹配这个异常对象 
        // 如果匹配上了 就执行 catch中的语句
        // 捕获异常后 程序会继续执行
        System.out.println("吃药没 ? 除数为0");
    }

class TestException{
    // 报异常方法
    public int fun(int a,int b) {
        /*
         * 这里发生了算数异常
         * 相当于 产生了异常对象
         * new ArithmeticException ("/ by zero")
         * 
         * 一旦发生异常 系统会产生一个对应异常现象
         * 发生异常后 谁调用我 这个异常就给谁
         * 处理不了 就给JVM虚拟机去处理 
         * JVM默认处理方法: 打印错误信息(根据异常对象的类型 去打印对应错误信息)
         * 然后打印完会结束你的程序
         * 
         */
        return a / b;
    }
}

使用多重的catch语句:很多情况下,由单个的代码段可能引起多个异常。处理这种情况,我们需要定义两个或者更多的catch子句,每个子句捕获一种类型的异常,当异常被引发时,每个catch子句被依次检查,第一个匹配异常类型的子句执行,当一个catch子句执行以后,其他的子句将被旁路。

编写多重catch语句块注意事项:

顺序问题:先小后大,即先子类后父类

public static void main(String[] args) {
        int[] array = {1,4,65,7};
        try {
            // 测试代码异常
            System.out.println(10/1);
            // 产生new ArithmeticException();
            // 之后就去匹配
            // 匹配成功后 程序继续向下执行
            System.out.println(array[12]);
        }catch (ArithmeticException e) {
            /*
             * 注意: 如果使用Exception直接匹配异常 
             * 多个catch同时捕获时 需要写在最后
             * 写前面 后面的catch相当于白写了
             */
            System.out.println("病了治 除数为0");
        }catch (ArrayIndexOutOfBoundsException e) {
            // 如果发生多个异常 需要匹配多个catch
            System.out.println("继续治疗吧 别放弃");
        }catch (Exception e) {
            System.out.println("你出错了");
        }

注意:

Java通过异常类描述异常类型。对于有多个catch子句的异常程序而言,应该尽量将捕获底层异常类的catch子句放在前面,同时尽量将捕获相对高层的异常类的catch子句放在后面。否则,捕获底层异常类的catch子句将可能会被屏蔽。

RuntimeException异常类包括运行时各种常见的异常,ArithmeticException类和ArrayIndexOutOfBoundsException类都是它的子类。因此,RuntimeException异常类的catch子句应该放在最后面,否则可能会屏蔽其后的特定异常处理或引起编译错误。

2.finally
记住: 不管你异常有没有发生 有没有被匹配到 都会执行

finally有什么作用?
可以关闭系统资源 避免资源的浪费
(例如 关闭输入流 和 关闭数据库)

例子:

  public static void main(String[] args) {
        try {
            System.out.println(10/1);
            return;
        } catch (ArithmeticException e) {
            System.out.println("除0");
        }finally {
            System.out.println("你看我执行了吗");
        }
        System.out.println("我是下面的语句");
    }

那么 final finally finalize有什么区别?

 没什么联系 一点关系没有
  final 用于修饰属性、方法和类,分别表示 属性不可变、方法不能被重写和类不可被继承
   final属性:被final修饰的变量不可变。由于不可变有两重含义:一是引用不可变;二是对象不可变。
   final方法:当一个方法被修饰为final时,该方法不允许任何子类重写这个方法,但子类仍可以使用这个方法。
   final类:当一个类被修饰为final时,此类不能被继承,所有方法都不能被重写。
   当这并不表示final类的成员变量也是不可改变的。

   finally:中语句 一定被执行(异常处理的语句)

   finalize:是Object类的一个方法 所有java中对象都有这个方法
   该方法在垃圾回收时候 被系统自动调用
   当一块内存空间 无人引用 这个块内存就是垃圾

3.运行时异常 和 编译时异常


  运行时异常 和 编译时异常
  除了运行时异常 就是编译时异常
  出现运行时异常---就是代码问题(程序员犯的错误)
  出现编译时异常---问题的提前预警 强制你去处理
                  不处理 编译不通过

public class Demo05 {
    public static void main(String[] args) throws FileNotFoundException {
        // 编译时异常 
        // 系统这时候 不知道你到底有没有这个文件
        // 相当于系统问你 要是没有这个文件咋整?
        // 这时系统会强制 要求你对这个问题作出解释
        // 这就是编译时异常(相当于对问题的 一种提前准备)
        // 
        /*
         * 解决异常有两张方式 
         * 1.自己处理 try..catch
         * (想让程序继续执行 就用try)
         * 2.把异常抛出去(谁调用我 抛给谁 谁去处理)
         * (向让程序遇到错误停止 就抛)
         */
        /*
        try {
            FileInputStream fileInputStream = new FileInputStream("wl.txt");
        } catch (Exception e) {
            System.out.println("读入文件没找到");
        }
        */

        FileInputStream fileInputStream = new FileInputStream("wl.txt");

    }

}

4 . throw和throws关键字的区别
throw用来抛出一个异常,在方法体内。语法格式为:throw 异常对象。
throws用来声明方法可能会抛出什么异常,在方法名后,语法格式为:throws 异常类型1,异常类型2…异常类型n。

5 . 自定义异常类
创建Exception或者RuntimeException的子类即可得到一个自定义的异常类。例如:
public class MyException extends Exception{
public MyException(){}
public MyException(String smg){
super(smg);
}
}

6、使用自定义的异常
用throws声明方法可能抛出自定义的异常,并用throw语句在适当的地方抛出自定义的异常。例如:
在某种条件抛出异常
public void test1() throws MyException{

if(….){
throw new MyException();
}
}

public static void main(String[] args) throws Exception{
        Prson prson = new Prson();
        prson.setAge(200);

        System.out.println(prson.getAge());
    }

}
// 创建一个人类
class Prson{
    // 姓名
    private String name;
    // 年龄
    private int age;


    public Prson(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Prson() {

    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    // 如果这个方法 要抛出异常 给调用者 那么必须在方法的声明上 标识出这个方法为异常方法
    // throws Exception 标识抛出什么异常

    /*
     * throws 和 throw 区别?
     * 1.throws 标识这个方法 可以抛出一个异常(方法的声明出现)
     *   throw 抛出一个异常对象(方法中出现)
     * 
     */
    public void setAge(int age) throws Exception{
        // 年龄的判断
        if (age > 0 && age < 120) {
            this.age = age;
        }else {
            // 抛出一个异常 告诉他你输入的不对
            // throw 关键字 抛出一个异常对象
            // 创建一个异常对象
            //Exception e = new Exception("年龄非法");
            // 把这个异常对象抛出去
            // 抛给谁? 谁用抛给谁
            // throw new Exception("年龄非法")
            // 使用自定义类处理异常
            AgeOutOfBoundsException e = new AgeOutOfBoundsException("年龄非法");
            throw e;
        }
    }
    @Override
    public String toString() {
        return "Prson [name=" + name + ", age=" + age + "]";
    }
}
// 创建一个自定义的异常类(继承 Exception)
// 再创建异常类时 需要直观让人知道这是什么异常
class AgeOutOfBoundsException extends Exception{


    // 重写构造方法
    public AgeOutOfBoundsException() {
        super();

    }

    public AgeOutOfBoundsException(String message) {
        super(message);
        // TODO Auto-generated constructor stub
    }


}

7.异常转译

将异常转型(也叫转译),使得异常更易读易于理解
public void test2() throws MyException{

try{

}catch(Exception e){

throw new MyException();
}
}

还有一个代码,很有意思:
public void test2() throws MyException{

try {

} catch (MyException e) {
throw e;
}
}

这段代码实际上捕获了异常,然后又和盘托出,没有一点意义,如果这样还有什么好处理的,不处理就行了,直接在方法前用throws声明抛出不就得了。异常的捕获就要做一些有意义的处理。

其实就是在
异常转译
必须捕获算数异常 但无权处理
将异常上抛 且进一步明确异常种类

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值