zoukankan      html  css  js  c++  java
  • java中的异常

    异常的基本概念
    异常的分类
    getMessage和printstackTrace
    finally关键字
    final、finalize和finally
    如何自定义异常及使用

    异常的基本概念
    • 异常概述
      1、什么是异常?
      程序执行过程中发生了不正常的情况,而这种不正常的情况叫做:异常。
      2、java提供异常处理机制有什么用?
      java语言是很完善的语言,提供了异常的处理方式。程序执行过程中出现了不正常情况,java把该异常信息打印输出到控制台,供程序员参考。程序员看到异常信息之后,可以对程序进行修改,让程序更加的健壮。
      3、java语言中异常是以什么形式存在的呢?
      异常在java中以类的形式存在,每一个异常类都可以创建异常对象。如:
    NumberFormatException nfe = new NumberFormatException("数字格式化异常");
            System.out.println(nfe);
    

    4、编译时异常和运行时异常,都是发生在运行阶段。编译阶段异常是不会发生的。
    因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错。所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象。异常的发生就是new异常对象。

    异常的分类
    • 编译时异常和运行时异常的区别
      1、编译时异常一般发生的概率比较高。运行时异常一般发生的概率比较低。
      2、对于一些发生概率较高的异常,需要在运行之前对其进行预处理。
      3、编译时异常还有其他名字:
      受检异常:CheckedException
      受控异常
      运行时异常还有其它名字:
      未受检异常:UnCheckedException
      非受控异制
    • 异常的两种处理方式
      1、
      第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。
      第二种方式:使用try...catch语句进行异常的捕捉。
      2、例子:
      某集团的一个销售员,因为失误,导致公司损失了1000元。
      “损失1000元"这可以看做是一个异常发生。
      有两种处理方式。第一种方式:把这件事告诉领导(异常上抛)第二种方式:自己掏腰包把这个钱补上。(异常的捕捉)
      3、注意:
      Java中异常发生之后如果一直上抛,最终抛给了main方法, main方法继续向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果。终止Java程序的执行。
    • 运行时异常编译时可以不处理
      代码示例:
    public class Demo{
        public static void main(String[] args){
            /*程序执行到此处发生了ArithmeticException异常
            底层new了—个ArithmeticException异常对象,然后抛出了。
            由于是main方法调用了10/0,
            所以这个异常ArithmeticException抛给了main方法。
            main方法没有处理,将这个异常自动抛给了JVM。
            JVM最终终止程序的执行。
            ArithmeticException继承RuntimeException,
            属于运行时异常。在编写程序阶段不需要对这种异常进行预先的处理。*/
            System.out.println(10/0);
            /*这里的hello world没有输出,没有执行。*/
            System.out.println("hello world!");
        }
    }
    
    • 方法声明位置上使用throws
      1、代码示例:
    public class Demo{
        public static void main(String[] args){
            /**
             * main方法中调用doSome()方法。
             * 因为doSome()方法声明位置上有:
             * throws ClassNotFoundException,
             * 我们在调用doSome()方法的时候必须
             * 对这种异常进行预先的处理。
             * 如果不处理,编译器就报错。
             * 编译器报错信息:
             * Unhandled exception: java.Lang.CLassNotFoundException
             * 报错原因:
             * 因为doSome()方法声明位置上使用了:
             * throws ClassNotFoundException
             * 而CLassNotFoundException是编译时异常。
             * */
            doSome();//报错
        }
        /**
        * doSome方法在方法声明的位置上使用了:
        * throws classNotFoundException。
        * 这个代码表示doSome()方法在执行过程中,
        * 有可能会出现CLassNotFoundException异常。
        * 这个异常直接父类是:Exception,
        * 所以CLassNotFoundException属于编译时异常。
        * @throws ClassNotFoundException
        */
        public static void doSome() throws ClassNotFoundException{
            System.out.println(111);
        }
    }
    

    2、处理
    第一种处理方式:
    在方法声明的位置上继续使用:throws来完成异常的继续上抛。抛给调用者。
    (上抛类似于推卸责任,继续把异常传递给调用者)

    public static void main(String[] args) throws ClassNotFoundException {
            doSome();
        }
    

    第二种处理方式:
    try...catch进行捕捉
    (捕捉等于把异常拦下了,异常真正的解决了。调用者是不知道的。)

    public static void main(String[] args){
            try {
                doSome();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
    • 异常捕捉和上报的联合使用
      1、报错代码示例:
    import java.io.FileInputStream;
    
    public class Demo{
        public static void main(String[] args){
            System.out.println("main begin");
            m1();
            System.out.println("main over");
        }
    
        public static void m1(){
            System.out.println("m1 begin");
            m2();
            System.out.println("m1 over");
        }
    
        public static void m2(){
            /*
            * 编译报错的原因是什么?
            * 第一:这里调用了一个构造方法:
            * FileInputstream(String name)
            * 第二:这个构造方法的声明位置上有:
            * throws FileNotFoundException
            * 第三:通过类的继承结构看到:
            * FileNotFoundException父类是TOException,
            * IOException的父类是Exception
            * 最终得知,FileNotFoundException是编泽时异常。
            * 所以编译时异常要求程序员编写程序阶段必须对它进行处理,
            * 不处理编译器就会报错。
            * */
            new FileInputStream("D:\111.txt");
        }
    
    
    }
    

    2、第一种处理方式:在方法声明的位置上使用throws关键字抛出,谁调用这个方法,就抛给谁。抛给调用者来处理。
    代码示例:

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    
    public class Demo{
        public static void main(String[] args) throws FileNotFoundException {
            System.out.println("main begin");
            m1();
            System.out.println("main over");
        }
    
        public static void m1() throws FileNotFoundException {
            System.out.println("m1 begin");
            m2();
            System.out.println("m1 over");
        }
    
        /*
        * 只能抛本身或者其父类,抛其它的没用。
        * throws后面也可以写多个异常,可以使用逗号隔开。
        * */
        public static void m2() throws FileNotFoundException {
            new FileInputStream("D:\111.txt");
        }
    
    }
    

    一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会地给JVM,JVM只有终止。异常处理机制的作用就是增强程序的健壮性,要做到异常发生了也不影响程序的执行。所以一般main方法中的异常建议使用try...catch进行捕捉。main就不要继续上抛了。
    3、第二种处理方式:使用try...catch语句对异常进行捕捉。

    try {
        //try尝试
        //出现异常直接进入catch语句块
    } catch (异常名 变量名) {
        //catch是捕捉异常之后走的分支。
    }
    

    代码示例:

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    
    public class Demo{
        public static void main(String[] args){
            System.out.println("main begin");
            try {
                m1();
            } catch (FileNotFoundException e) {
                //e.printStackTrace();
                System.out.println("文件不存在!");
            }
            System.out.println("main over");
        }
    
        public static void m1() throws FileNotFoundException {
            System.out.println("m1 begin");
            m2();
            System.out.println("m1 over");
        }
    
        public static void m2() throws FileNotFoundException {
            new FileInputStream("D:\111.txt");
        }
    
    }
    

    输出:
    在这里插入图片描述
    或:

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    
    public class Demo{
        public static void main(String[] args){
            System.out.println("main begin");
            m1();
            System.out.println("main over");
        }
    
        public static void m1(){
            System.out.println("m1 begin");
            m2();
            System.out.println("m1 over");
        }
    
        public static void m2(){
            try {
                new FileInputStream("D:\111.txt");
            } catch (FileNotFoundException e) {
                //e.printStackTrace();
                System.out.println("文件不存在!");
            }
        }
    
    }
    

    输出:
    在这里插入图片描述

    • 深入try...catch
      1、catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型。
      2、catch可以写多个。建议catch的时候,精确地一个一个处理。这样有利于程序的调试。
      3、catch写多个的时候,从上到下,必须遵守从小到大。
      4、java8新特性
      代码示例:
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    
    public class Demo{
        public static void main(String[] args){
            try {
                FileInputStream fis = new FileInputStream("D:\111.txt");
                System.out.println(100 / 0);
            } catch (FileNotFoundException | ArithmeticException e) {
                //e.printStackTrace();
                System.out.println("文件不存在?数学异常?都有可能!");
            }
        }
    }
    
    • 处理编译异常时,如何选择上报还是捕捉?
      如果希望调用者来处理,选择throws上报。
      其它情况使用捕捉的方式。
    getMessage和printstackTrace
    • 异常对象的常用方法
      1、获取异常简单的描述信息:
      string msg = exception.getMessage();
      2、取得异常的堆栈信息(比较适合于程序调试阶段):
      exception.printstackTrace();
      (一般使用这种,try...catch里就是这种)
      代码示例:
    public class Demo{
        public static void main(String[] args){
            NullPointerException n = new NullPointerException("空指针异常");
            String msg = n.getMessage();
            System.out.println(msg);
            n.printStackTrace();
        }
    }
    

    输出:
    在这里插入图片描述

    finally关键字
    • 关于try..catch中的finally子句
      1、finally子句中的代码是最后执行的,并且是一定会执行的。(即使try语句块中的代码出现了异常)
      finally子句必须和try一起出现,不能单独编写。
      2、finally语句通常使用在哪些情况下呢?
      通常在finally语句块中完成资源的释放/关闭。
      因为finally中的代码比较有保障。
      即使try语句块中的代码出现异常,finally 中代码也会正常执行。
      3、代码示例:
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    public class Demo{
        public static void main(String[] args){
            FileInputStream fis = null;
            try {
                //创建输入流对象
                fis = new FileInputStream("D:\111.txt");
                //这里一定会出现空指针异常
                String s = null;
                s.toString();
                /*
                流使用完需要关闭,因为流是占用资源的。
                但是上面的程序出现异常,导致不能关闭流。
                */
                //fis.close();
                System.out.println(111);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NullPointerException e){
                e.printStackTrace();
            }
            finally {
                System.out.println(222);
                /*
                * 流的关闭放在这里比较保险。
                * 即使try中出现了异常。
                * finally中的代码是一定会执行的。
                * */
                if (fis != null){
                    try {
                        //close()方法有异常,采用捕捉的方式。
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println(333);
        }
    }
    

    输出:
    在这里插入图片描述

    • 退出JVM,finally语句不执行
      代码示例:
    public class DemoTest{
        public static void main(String[] args) {
            /*
            * 没有catch,
            * 只有try和finally也可以。
            * 以下代码的执行顺序:
            * 先执行try...
            * 再执行finally...
            * 最后执行return(return语句只要执行方法必然结束)
            * */
            try{
                System.out.println("try...");
                return;
                /*只有退出JVM,finally语句中的代码才不会执行。
                * System.exit(0);
                * */
            }finally {
                System.out.println("finally...");
            }
        }
    }
    

    输出:
    在这里插入图片描述
    将return替换为:

    System.exit(0);
    

    输出:
    在这里插入图片描述

    • 关于finally的一道题
      代码示例:
    public class Demo{
        public static void main(String[] args){
           int n = m();
            System.out.println(n);
        }
        public static int m(){
            int i = 100;
            try {
                return i;
            }finally {
                i++;
            }
        }
    }
    

    输出:
    在这里插入图片描述
    因为:

    /*
    反编译后的代码为:
    */
    public static int m() {
            byte i = 100;
    
            byte var1;
            try {
                var1 = i;
            } finally {
                int i = i + 1;
                System.out.println(i);
            }
    
            return var1;
        }
    
    final、finalize和finally
    • 代码示例
    public class Demo{
        public static void main(String[] args){
            /*final是一个关键字,表示最终的。不变的。*/
            final int i = 10;
            /*
            finally也是一个关键字,和ry联合使用。
            使用在异常处理机制中,
            在finally语句块中的代码是一定会执行的。
            */
            try {
    
            }finally {
                System.out.println("finally...");
            }
            /*
            finalize()是object类中的一个方法。
            作为方法名出现,所以finalize是标识符。
            */
        }
    }
    
    如何自定义异常及使用
    • 自定义异常
      第一步:编写一个类继承Exception或者RuntimeException。
      第二步:提供两个构造方法,一个无参数的,一个带有String参数的。
    • 继承Exception或者RuntimeException
      继承Exception:(编译时异常)
    /*编译时异常*/
    public class MyException extends Exception{
        public MyException() {
        }
    
        public MyException(String message) {
            super(message);
        }
    }
    

    继承RuntimeException:(运行时异常)

    /*运行时异常*/
    public class MyExcption extends RuntimeException{
        public MyExcption() {
        }
    
        public MyExcption(String message) {
            super(message);
        }
    }
    
    • 代码示例:
    /*编译时异常*/
    public class MyException extends Exception{
        public MyException() {
        }
    
        public MyException(String message) {
            super(message);
        }
    }
    
    public class MyExceptionTest {
        public static void main(String[] args) {
            //创建异常对象(只new了异常对象,并没有手动抛出)
            MyException e = new MyException("用户名不能为空!");
            //打印异常堆栈信息
            e.printStackTrace();
            //获取异常简单描述信息
            String msg = e.getMessage();
            System.out.println(msg);
        }
    }
    

    输出:
    在这里插入图片描述

    • 异常在实际开发中的作用
      代码示例:
    public class MyException extends Exception{//编译时异常
        public MyException() {
        }
    
        public MyException(String message) {
            super(message);
        }
    }
    
    public class Demo{
        public void Demo(int x) throws MyException {
            if(x < 0){
                /*改良前*/
                //System.out.println("请输入大于0的数!");
                //return;
                /*改良后*/
                throw new MyException("请输入大于0的数!");
            } else {
                System.out.println(x);
            }
        }
    }
    
    public class DemoTest{
        public static void main(String[] args) {
            Demo demo = new Demo();
            try {
                demo.Demo(1);
                demo.Demo(2);
                demo.Demo(-3);
                demo.Demo(4);
            } catch (MyException e) {
                //e.printStackTrace();
                System.out.println(e.getMessage());
            }
        }
    }
    

    输出:
    在这里插入图片描述

    • 重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,但是可以更少。
  • 相关阅读:
    通过Maven简单搭建SSM框架
    javaWeb常用面试题
    到底什么是对象,什么是对象的引用?对象和对象的引用有那些区别?
    第二章 python中重要的数据结构(下)
    第一章 python中重要的数据结构(上)
    springboot 集成完整的swagger2
    JAVA -> 数据加密和解密 留存
    mac rar文件解压缩
    java 图片合成文字或者awt包下的对话框引入自定义字体库
    java中list或数组中随机子集工具类
  • 原文地址:https://www.cnblogs.com/yu011/p/12716255.html
Copyright © 2011-2022 走看看