Day18.异常、异常的处理机制、自定义异常及应用、常用方法

目录

什么是异常

异常体系结构

异常处理机制

捕获异常(try...catch...finally)

抛出异常(throw、throws)

关于finally的面试题  

异常对象的常用方法 

自定义异常(重点)

习题


什么是异常

  • 软件程序在运行过程中,可能遇到各种意外,我们称为异常(Exception),让我们写的程序作出合理的处理,而不至于崩溃。

  • 异常发生在程序运行期间出现的不期而至的各种状况,影响正常的程序执行流程。如:文件缺失、网络连接失败、非法参数等。

  • 要理解Java异常处理是如何工作的,你需要掌握以下三种类型异常:
  • 检查性(编译时)异常(CheckedException):最具代表性的检查性异常是用户错误或问题引起的异常,如要打开一个不存在文件时,异常就发生了,这些异常在编译时不能被简单的忽略。

  • 运行时异常(RuntimeException):与检查性异常相反,运行时异常可以在编译时容易被忽略,只有在运行时才能看到。

  • 错误(ERROR):错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略,如:栈溢出时,一个错误就发生了,它们在编译时无法被检测。

异常体系结构

  • Java把异常当做对象来处理,并定义了一个基类java.lang.Throwable(可抛出的)作为所有异常的超类

  • 在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。

错误(Error)

  • Error类对象由 Java 虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关

  • Java运行错误(Virtual MachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时候,Java虚拟机(JVM)一般会选择线程终止;

  • 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为他们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。

异常(Exception)

  • 在Exception分支中有一个重要的子类RunTimeException(运行时异常)

    • ArrayLndexOutOfBoundsExecption(数组下标越界)

    • NullPointerExeception(空指针异常)

    • ArtithmeticException(算数异常)

    • MissingResourceException(资源丢失)

    • ClassNotFoundException(找不到类)

    这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。

  • 这些异常一般是由程序员逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生

  • Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程:Exception通常是可以处理的,并且在程序中应该尽可能的处理这些异常。

异常处理机制

  • 异常机制使程序更健壮因为捕捉异常后程序不会停止!

  • 对于异常的处理可使用两种方式
    • 在方法声明的位置上,使用throws关键字,抛给上一级。

    • 使用try...catch语句进行异常的捕捉。

  • 异常处理的五个关键字

    • try、catch、finally ; throw、throws

  • 通常在finally语句中完成资源的释放/关闭。

捕获异常(try...catch...finally)

    public static void main(String[] args) {
        int a = 1;
        int b = 0;
        //System.out.println(a/b);  //ArithmeticException算数异常
        try {                       //try 监控区域
            System.out.println(a/b);

        //e引用保存内存地址 指向new出来的异常对象
        } catch (ArithmeticException a) {     //catch(想要捕获的异常类型)
            System.out.println("Exception:程序出现异常,变量b不能为0");
        } catch (Exception e){      //多态:Exception e = new ArithmeticException();
                                    //可以捕获多个异常,需要从小到大捕获。建议精确,有利于调试
                                    //ArithmeticException< Exception< Tgriwable
            System.out.println("Throwable");
        }finally {                 //无论是否出现异常finally都会被执行
            System.out.println("无论是否出现异常finally都会被执行");
        }

        //finally 如IO 流使用完因为占用资源需要关闭,可写在finally中 close();

        //快捷键:选中代码后Ctrl Alt+T
    }
  • 捕捉相当于将异常拦下,异常真正的处理了。

  • 在多重catch块最后面,可以加一个catch(Exception)来处理可能会被遗漏的异常。

  • try...finally可以联用

    public static void main(String[] args) {
        try {
            System.out.println("try...");
            return;            //结束
        } finally {            //finall语句块内是一定被执行的
            System.out.println("finally...");
        }
        //代码无法被执行到
        //System.out.println("HelloWorld");   //报错:Unreachable statement
    }

抛出异常(throw、throws)

实际项目时,底层异常一般上抛到某一层面统一进行处理。

  • 如果希望使用者来处理,选择throws(上抛)。(比如 FileNotFoundException文件丢失异常)

注:子类继承父类,不能比父类抛出更多的异常

    public static void main(String[] args) {
        new Test().test(1,0);
    }

    //假设方法中处理不了这个异常,就在方法上抛出异常 若调用这个方法就需要处理这个异常
    public void test(int a,int b) throws ArithmeticException{
        if(b==0){  //区分 throw throws
            throw new ArithmeticException();//主动抛出异常,一般在方法中使用
        }
    }

 上抛类似于甩锅,继续把异常异常传递给调用者。

    public static void main(String[] args) {
        //编译时异常不进行处理,就会报错
        doSome();   //Unhandled exception: java.lang.ClassNotFoundException
    }
    public static void doSome()throws ClassNotFoundException{
        System.out.println("doSome");
    }

关于finally的面试题  


    //面试题1:finally什么情况不会被执行?
    //1.System.exit()中止当前虚拟机(JVM)时。
    //2.守护(daemon)线程被中止时


    //面试题2:以下代码将输出?
    public static void main(String[] args) {
        System.out.println(m());     //100
    }
    public static int m(){
        int i = 100;
        try{
            return i;
        }finally{            //finally语句块是一定最后被执行的
            i++;
        }
    }
    /*
    Java语法规则(有一些规则是不能破坏的)
        方法体重的代码必须遵循自上而下的顺序依次执行。
        return语句一旦执行,整个方法必须结束。
    反编译之后的效果
    public static int m (){
        int i = 100;
        int j = i;
        i++;
        return j;
    }*/

    //笔试题3:final finally finalize 有什么区别?
    public static void main(String[] args) {
        //1.final是一个关键字。表示最终的。
        final int i = 100;
        //修饰的类无法继承、方法无法覆盖、变量无法重新赋值。

        //2.finally也是一个关键字,和try联合使用,在异常处理机制中。
        //finally语句块内的代码是一定会被执行的。
        try{
        }finally{
            System.out.println("finally...");
        }
        
        //3.finalize()是Object类中的一个方法,已过时。
        //该方法是JVM的GC垃圾回收期负责调用。
        //finalize作为方法名出现,所以finalize是标识符。
     */

    //

异常对象的常用方法 

  • 获取异常简单的描述信息:  (实际上是异常构造方法上面String参数)

    • String msg = exception.getMessoge();

NullPointerException e = new NullPointerException("空指针异常!");
System.out.println(e.getMessage()); //空指针异常!
  • 打印异常追踪的堆栈信息:

    • exception.printStackTrace();   

NullPointerException e = new NullPointerException("空指针异常!");
e.printStackTrace();                    //采用了异步线程的方式打印。(多线程)
//实际开发中,建议使用。养好好习惯,不然出了问题你也不知道!

注:查看异常追踪信息时由,自己写的代码开始从上往下看。

自定义异常(重点)

        SUN提供的JDK内置异常肯定是不够用的。在实际开发中,有很多业务出现异常中,JDK中都是没有的,也和业务挂钩的,那么我们便需要自定义异常。

  • 如何自定义异常?  (灵感来自于SUN公司)

    • 编写一个类继承Exception或RuntimeException

    • 提供两个构造方法,一个无参,一个有参。

public class MyException extends Exception {        //编译时异常  发生概率高
    public MyException(){ }         //无参构造
    public MyException(String s){   //有参构造
        super(s);
    }
}
public class MyException extends RuntimeException { //运行时异常  发生概率低
    public MyException(){ }
    public MyException(String s){
        super(s);
}
  • 自定义异常的应用
public class test2 {
    public static void main(String[] args) {
        //创建异常对象   只new了对象,未抛出
        MyException e = new MyException("用户名不能为空!");

        //打印异常堆栈信息
        e.printStackTrace();

        //获取异常简单描述信息
        String msg = e.getMessage();     //用户名不能为空!
    }
}

习题

编写程序模拟用户注册:
1、程序开始执行时,提示用户输入“用户名”和“密码”信息。
2、输入信息之后,后台java程序模拟用户注册。
3、注册时用户名要求长度在[6-14]之间,小于或者大于都表示异常。
注意:
    完成注册的方法放到一个单独的类中。
    异常类自定义即可。

    class UserService {
        public void register(String username,String password){
            //这个方法中完成注册!
        }
    }

    编写main方法,在main方法中接收用户输入的信息,在main方法
    中调用UserService的register方法完成注册。

public class UserService {

    public void register(String username,String password)throws UserServiceException{
        //如果用户名越界
        if (username.length()<6 || username.length()>16){
            //抛出新建的异常,输入简单信息
           throw new UserServiceException("用户名越界,请重新输入");
        }
    }
}
//照葫芦画瓢,创建新异常,用户服务异常
public class UserServiceException extends Exception{
    public UserServiceException(){}
    public UserServiceException(String s){
        super(s);
    }
}
public class TestUser {
    public static void main(String[] args) {
        UserService a = new UserService();

        Scanner scanner = new Scanner(System.in);

        System.out.println("欢迎使用注册系统,请输入用户名!");
        String u = scanner.next();
        System.out.println("用户名为"+u+",请输入密码!");
        String p = scanner.next();

        boolean flag = false;   //用于判断用用户是否创建成功
        do{
            try{
                a.register(u,p);
                flag = true;    //跳出循环
                System.out.println("注册成功");  //如果失败,抛出异常,注册失败。
            } catch (UserServiceException e) {
                System.out.println(e.getMessage());
                u = scanner.next();             //重新输入用户名
            }
        }while(flag = false);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值