java中的异常、处理异常的方法、getMessage和printStackTrace方法、finally语句块、自定义异常&手动抛出异常

java中的异常、处理异常的方法、getMessage和printStackTrace方法、finally语句块、自定义异常&手动抛出异常

1、异常的定义及其作用

package com.company.exception;
/*
* 1、异常是什么?
*   第一、异常模拟的是现实世界中“不正常的”事件
*   第二、java中采用“类”去模拟异常
*   第三、类是可以创建对象的
*       NullPointerException e = 0x1234;
*       e是引用类型,e中保存的内存地址指向堆中的“对象”
*       这个对象一定是NullPointerException类型
*       这个对象就表示真实存在的异常事件
*       NullPointerException是一类异常
*
* 2、异常机制的作用?
*   java语言为我们提供了一种完善的异常处理机制
*   作用是:程序发生异常事件之后,为我们输出详细的信息。
*   程序员通过这个信息,可以对程序进行一些处理,使程序
*   更加健壮
* */
public class ExceptionTest01 {
    public static void main(String[] args) {

        int a = 10;
        int b = 0;
        int c = a / b;  // ArithmeticException e = oxxxxx;

        // 上面的代码出现异常,“没有处理”,下面的代码不会执行,直接退出JVM
        System.out.println("hello world!");
    }
}
/*
* 以上程序编译通过了,但是运行时出现了异常,表示发生了某个异常事件。
* JVM向控制台输出如下的信息:
*   Exception in thread "main" java.lang.ArithmeticException: / by zero
*	    at com.company.exception.ExceptionTest01.main(ExceptionTest01.java:20)
*本质:程序执行过程中发生了算数异常这个事件,JVM为我们创建了一个ArithmeticException类型的对象。
*并且这个对象中包含了详细的异常信息,并且JVM将这个对象中的信息输出到控制台。
* */

在这里插入图片描述

2、处理异常的两种方法:

2.1 第一种方法:声明抛出 throws
package com.company.exception;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/*
* 处理异常有两种方法:
*   1、声明抛出
*       throws
*
*   2、捕捉
*       try...catch...
*
* 以下程序演示第一种方式:声明抛出,在方法声明的位置上使用throws关键字向上抛出异常。
* */
public class ExceptionTest02 {

    //public static void main(String[] args) {

        // 创建文件输入流,读取文件
        // 思考:java编译器是如何知道以下的代码执行过程中可能出现异常,java编译器是如何知道这个异常发生的几率比较高呢?
        // 实际上编译器并没有那么智能,这是因为在声明构造方法的时候写了throws FileNotFoundException
        /*
          public FileInputStream(String name) throws FileNotFoundException {
                 this(name != null ? new File(name) : null);
            }

        */
    //    FileInputStream fis = new FileInputStream("c:/ab.txt");  // 文件不存在
    //}

    // 第一种方法:声明抛出
    // 这是编译不会出错
    // ① public static void main(String[] args) throws FileNotFoundException {
    // ② public static void main(String[] args) throws IOException {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("c:/ab.txt");
    }

}
/*
* 以上程序编译不通过
* Error:(19, 31) java: 未报告的异常错误java.io.FileNotFoundException; 必须对其进行捕获或声明以便抛出
* */

2.2 深入了解 throws
package com.company.exception;
/*
* 深入throws
* */
import java.io.*;
public class ExceptionTest03 {
    public static void main(String[] args) throws FileNotFoundException{
        //m1();

        // 使用throws处理异常不是真正的处理异常,而是推卸责任
        // 谁调用了就会抛给谁
        // 上面的m1方法如果出现了异常,因为采用的是上抛,给了JVM,JVM遇到这个异常就会退出JVM,下面的代码就不会执行

        // 真正处理:
        try{
            m1();
        }catch(FileNotFoundException e){}

        System.out.println("hello world!");
    }

    public static void m1() throws FileNotFoundException{
        m2();
    }

    public static void m2() throws FileNotFoundException{
        m3();  // 此时这里会出现编译异常,需要加throws,依次类推m1()、main()方法声明均需要加入throws
    }

    public static void m3() throws FileNotFoundException{
        new FileInputStream("c/ab.txt"); // FileInputStream构造方法声明位置上使用throws(向上抛)
    }
}

/*
* // 在程序运行过程中发生了FileNotFoundException类型的异常
* // JVM为我们创建了一个FileNotFoundException类型的对象
* // 该对象中携带以下的信息
* // JVM负责将该对象的信息打印到控制台,并且JVM停掉了程序的运行
* Exception in thread "main" java.io.FileNotFoundException: c\ab.txt (系统找不到指定的路径。)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
	at com.company.exception.ExceptionTest03.m3(ExceptionTest03.java:25)
	at com.company.exception.ExceptionTest03.m2(ExceptionTest03.java:21)
	at com.company.exception.ExceptionTest03.m1(ExceptionTest03.java:17)
	at com.company.exception.ExceptionTest03.main(ExceptionTest03.java:8)
* */
2.3 第二种方法: try…catch…
package com.company.exception;

import java.io.*;

/*
* 处理异常的第二种方式:
*   捕捉
*   try...catch...
*
* 语法:
*   try{
*       可能出现异常的代码;
*   }catch(异常类型1 变量){
*       处理异常的代码;
*   }catch(异常类型2 变量){
*       处理异常的代码;
*   }...
*
*   1、catch语句块可以写多个
*   2、但是从上到下catch,必须从小型异常到大型异常进行捕捉。
*   3、虽然小型异常可以去掉,但是为了更加准确的找到异常,最好不要舍掉。
*   4、try...catch...中最多执行1个catch语句块。执行结束之后try...catch...就结束了
* */
public class ExceptionTest04 {
    public static void main(String[] args) {
        // 情况①
        // 以下代码编译无法通过,因为FileNotFoundException没有处理。
        /*
        try{
            // 下面语句是FileNotFoundException异常
            FileInputStream fis = new FileInputStream("c:/ab.txt");
        }catch(ArithmeticException e){ //捕获的代码是算术异常

        }
         */


        // 情况②
        // 以下程序编译通过
        /*
        try{
            // 下面语句是FileNotFoundException异常
            FileInputStream fis = new FileInputStream("c:/ab.txt");
        }catch(FileNotFoundException e){

        }
        */


        // 情况③
        // 以下程序编译无法通过
        // 因为还有更多的IOException没有处理
        /*
        try{
            // 下面语句是FileNotFoundException异常
            FileInputStream fis = new FileInputStream("c:/ab.txt");

            fis.read();  // 因为它抛出的是throws IOException异常

        }catch(FileNotFoundException e){

        }

         */


        // 情况④
        // 以下编译可以通过
        /*
        try{
            // 下面语句是FileNotFoundException异常
            FileInputStream fis = new FileInputStream("c:/ab.txt");

            fis.read();  // 因为它抛出的是throws IOException异常

        }catch(FileNotFoundException e){

        }catch(IOException e){

        }
         */


        // 情况⑤
        /*
        // 这个也是编译通过的,因为IOException包含FileNotFoundException
        try{
            // 下面语句是FileNotFoundException异常
            FileInputStream fis = new FileInputStream("c:/ab.txt");

            fis.read();  // 因为它抛出的是throws IOException异常

        }catch(IOException e){

        }
         */

        // 情况⑥
        // 这个也会报错,因为IOException包含FileNotFoundException,程序自上而下
        // 第二个catch永远不会执行到,因此会报错。
        // 【注】catch可以写多个,但是必须从上到下,从小到大捕捉!!!
        /*
        try{
            // 下面语句是FileNotFoundException异常
            FileInputStream fis = new FileInputStream("c:/ab.txt");

            fis.read();  // 因为它抛出的是throws IOException异常

        }catch(IOException e){

        }catch(FileNotFoundException e){

        }
         */

    }
}

2.4 一个小例子
package com.company.exception;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ExceptionTest05 {
    // 编译无法通过
    // IOException没有处理
    /*
    public static void main(String[] args) throws FileNotFoundException{
        FileInputStream fis = new FileInputStream("c:/ab.txt");
        fis.read();
    }
     */

    // 通过
    /*
    public static void main(String args[]) throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream("c:/ab.txt");
        fis.read();
    }
     */

    public static void main(String args[]){

        // 程序执行到此处发生了FileNotFoundException类型的异常
        // JVM会自动创建一个FileNotFoundException类型的对象,该对象的内存地址赋值给catch语句中的e变量
        try{
            FileInputStream fis = new FileInputStream("c:/ab.txt");
            //上面的代码出现了异常,try语句块的代码不再继续执行,直接进入catch语句块中执行。
            System.out.println("TTTTTTTTTTT");  // 这句话并没有执行
            fis.read();
        }catch(FileNotFoundException e){  // 内存地址指向堆中的那个对象是“FileNotFoundException类型的”事件
            System.out.println("读取的文件不存在");

            // 说明FileNotFoundExceptiom将Object中toString方法重写了
            System.out.println(e); //java.io.FileNotFoundException: c:\ab.txt (系统找不到指定的文件。)
        }catch(IOException e){
            System.out.println("其他IO异常");
        }

        // 下面代码会执行
        // catch里面程序语句有执行,就默认异常有处理,下面的就可以执行了
        System.out.println("hello world!");

    }
}

3、关于getMessage和printStackTrace方法的应用

package com.company.exception;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/*
* 关于getMessage和printStackTrace方法的应用
* */
public class ExceptionTest06 {
    public static void main(String[] args) {
        try{
            FileInputStream fis = new FileInputStream("c:/abc.txt");

            // JVM为我们执行了一下这段代码,这是我们看不到的
            // FileNotFoundException e = new FileNotFoundException("c:/abc.txt");
            // 然后输出异常是调用了e.getMessage();方法
        }catch(FileNotFoundException e){

            // 打印异常堆栈信息
            // 一般情况下都会使用该方式去调试程序
            e.printStackTrace();
            /*
            java.io.FileNotFoundException: c:\abc.txt (系统找不到指定的文件。)
	            at java.base/java.io.FileInputStream.open0(Native Method)
                at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
                at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
                at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
                at com.company.exception.ExceptionTest06.main(ExceptionTest06.java:12)

             */

            // 上面的方式会常用一点,因为信息比较详细

            String msg = e.getMessage();
            System.out.println(msg);  //c:\abc.txt (系统找不到指定的文件。)
        }

        // 这段代码会执行
        System.out.println("ABC...");
    }
}

4、关于finally语句块

package com.company.exception;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

/*
* 关于finally语句块
*   1、finally语句块可以直接和try语句块联用。  try....finally...
*   2、try....catch....finally 也可以
*   3、在finally语句中的代码块是一定会执行的
*
* */
public class ExceptionTest07 {
    public static void main(String[] args) throws FileNotFoundException {
        /*
        try{
            System.out.println("ABC");
            return ;
        }finally{
            System.out.println("Test");
        }
         */



        /*
        try{
            FileInputStream fis = new FileInputStream("c:/ab.txt");
            // 下一句代码不会执行
            System.out.println("TTTTT");
        }finally{
            // 异常上抛没有解决,IOException没有处理,仍然会报错
            // 即使这样下面的语句还是执行了
            System.out.println("AAAAAAA");
        }
         */


        // 只有在执行finally语句块之前退出JVM,则finally语句块不会执行
        try{

            // 退出JVM
            System.exit(0);
        }finally{

            // 没有执行
            System.out.println("BBBBB");
        }

    }
}

深入finally语句块的一个小例子

package com.company.exception;
/*
* 深入finally语句块
* */
public class ExceptionTest08 {
    public static void main(String[] args) {

        int i = m1();
        System.out.println(i);  // 10
    }

    public static int m1(){

        int i = 10;
        try{
            return i;
        }finally{
            i++;
            System.out.println("m1()-->" + i);     // m1()-->11
        }


        // 以上代码的执行原理
        /*
        int i = 10;
        try{
            int temp = i;
            return temp;
        }finally{
            i++;
            System.out.println("m1()-->" + i);
        }
        */
    }
}

finally语句块的应用

package com.company.exception;

import java.io.*;

/*
* finally语句是一定会执行的,所以通常在程序中
* 为了保证某资源一定会释放,所以一般在finally语句块中释放资源
* */
public class ExceptionTest09 {
    public static void main(String[] args) {

        //声明一个文件流类型,由于大括号作用域的原因{}
        FileInputStream fis = null;

        try{
            fis = new FileInputStream("ExceptionTest08.java");
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }finally{
            // 为了保证资源一定得到释放
            if(fis == null){
                try{
                    fis.close();  // 文件流关闭也会引起IOException
                }catch(IOException e){
                    e.printStackTrace();
                }

            }
        }

    }
}

5、自定义异常&手动抛出异常

自定义异常&手动抛出异常的一个例子

package com.company.exception;
/*
* 如何手动抛出异常?如何自定义异常?
*
* 自定义有两种方向:
*   1、编译时异常,直接继承Exception
*   2、运行时异常,直接继承RuntimeException
*
* 例子:自定义”无效名字的异常“(名字长度不能小于6),然后动手抛出异常信息。
* */
// 自定义异常
public class IllegalNameException extends Exception{   //编译时异常
//public class IllegalName Exception extends RuntimeException{  //运行时异常

    // 定义异常一般提供两个构造方法
    public IllegalNameException(){}

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

package com.company.exception;

// 顾客提供相关的业务
public class CustomerService {

    // 对外提供一个注册的方法
    public void register(String name) throws IllegalNameException{

        // 检查名字长度是否小于6位
        if(name.length() < 6){
            // 非法名字异常

            // 创建异常对象
            //IllegalNameException e = new IllegalNameException("用户名长度不能小于6位");

            // 手动抛出异常
            //throw e;

            // 或者一步搞定
            throw new IllegalNameException("用户名长度不能小于6位");

            /*
            【注意】:
             这里有一个重点需要注意:手动抛出的异常在register方法中编译会报错,需要做处理,
             而此处异常处理应该采用 throws 还是 try...catch...?

             try...catch...:是捕获异常,然后对异常进行处理
                  我们手动抛出的异常,如果在此处又我们手动捕获给处理掉,完全就没有意义了。


             所以应该采用 throws 向上抛,然后再在顾客调用register方法的时候对其进行异常检测捕获。
            */
        }

        System.out.println("注册完成");
    }
}
package com.company.exception;
/*
* 模拟注册
* */
public class Test {
    public static void main(String[] args) {
        // 提供用户名
        String username = "jack";

        // 注册
        CustomerService c = new CustomerService();

        // 如果有异常,就获取,然后进行相关操作
        try{

            c.register(username);
        }catch(IllegalNameException e){

            System.out.println(e.getMessage());
        }

        // 如果没有异常,就执行完register()函数,输出“注册成功”
    }
}

6、在方法重写时说到的一点:重写的方法不能比被重写的方法抛出更宽泛异常。具体指的是什么?

package com.company.exception;

import java.io.FileNotFoundException;
import java.io.IOException;

/*
* 重写的方法不能比被重写的方法抛出更宽泛异常
* */
public class ExceptionTest10 {

}

class A{
    public void m1(){}
}

class B extends A{
    // 下面这句会报错,因为重写的方法不能比被重写的方法抛出更多的异常
    // 父类中m1()方法没有抛出异常,而子类中m1()方法却抛出异常

   // public void m1() throws Exception{}
}


class C{
    public void m2() throws FileNotFoundException {}
}

class D extends C{
    // 下面这句会报错,因为FileNotFoundException属于IOException
    // 重写的方法不能比被重写的方法抛出更高等级的异常

    //public void m2() throws IOException{}
}


class E{
    public void m2() throws IOException{}
}

class F extends E{
    // 这个编译就没有任何问题
    public void m2() throws FileNotFoundException {}
}
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值