Java学习第七章

视频链接:https://www.bilibili.com/video/BV1Rx411876f?p=1

视频范围P629 - P659

异常

1.异常概述

  1. 异常:以下程序执行过程中发生了不正常的情况
package exception;

public class ExceptionTest01 {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        int c = a / b;
        System.out.println(c);
    }
}

JVM打印的异常信息

Exception in thread “main” java.lang.ArithmeticException: / by zero
at exception.ExceptionTest01.main(ExceptionTest01.java:7)

  1. java提供异常处理机制作用:java把异常信息打印输出到控制台,供程序员参考,看到异常信息之后,可以对程序进行修改,让程序更加健壮
  2. 当上面代码中,JVM执行到int c = a / b;会new异常对象:new ArithmeticException(" / by zero "),并且JVM将new的异常对象抛出,打印输出信息到控制台了

2.异常存在形式

  1. 异常在java中以类的形式存在,每一个异常类都可以创建异常对象
  2. 异常对应的现实生活:
    类是:模板
    对象是:实际存在的个体

    比如:
    火灾是(异常类);
    2022年3月13日,小红家着火了(异常对象)
package exception;

public class ExceptionTest02 {
    public static void main(String[] args) {

        //通过“异常类”实例化“异常对象”
        NumberFormatException nfe = new NumberFormatException("数字格式化!");
        System.out.println(nfe);//输出为:java.lang.NumberFormatException: 数字格式化!

        NullPointerException npe = new NullPointerException("空指针异常发生了!");
        System.out.println(npe);//输出为:java.lang.NullPointerException: 空指针异常发生了!
    }
}

3.异常的继承结构

3.1 UML图

  1. UML是一种统一建模语言,一种图标式语言(画图的)
  2. UML不是只有java中使用,只要是面向对象的编程语言都有UML
  3. 画UML图的都是:软件架构师或者系统分析师,或者软件设计人员
  4. UML图中可以描述类和类之间的关系,程序执行的流程,对象的状态
  5. 画UML图的工具:Rational Rose(收费)、starUML(免费)…

3.2 异常的继承结构图

  1. Object
  2. Object下有Throwable(可抛出的)
  3. Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)
  4. Exception下有两个分支:
    Exception的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理,编译器报错)
    RuntimeException:运行时异常(在编写程序阶段程序员可以预先处理,也可以不管)

使用starUML绘制:
在这里插入图片描述

3.3 编译时异常 和 运行时异常 区别

  1. 这两个异常多是发生在运行阶段,编译阶段这两个异常是不会发生的
  2. 编译时异常命名由来:因为编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错
  3. 所有异常都是在运行阶段发生的,因为只有程序运行阶段才可以new对象(异常的发生就是new异常对象)
  4. 编译时异常又被称为受检异常(CheckedException)、受控异常
  5. 运行时异常又被称为未受检异常(UnCheckedException)、非受控异常
  • 编译时异常一般发生的概率比较高
    举例:你看见外面下雨,倾盆大雨,你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)。而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。
    “拿把伞”就是对“生病异常”发生之前的一种处理方式
    对一些发生概率较高的异常,需要在运行之前对其进行预处理

  • 运行时异常一般发生的概率比较低
    举例:小明走在大街上,可能会被天上的飞机轮子砸到(被砸到也是一种异常)。但是这种异常发生概率较低。
    在出门之前没必要提前对这种发生概率较低的异常进行预处理,如果进行预处理,就会很累。

  • 如果java没有对异常进行划分,没有分为:编译时异常 和 运行时异常
    那么所有的异常都需要在编写程序阶段对其进行预处理,虽然程序这样肯定是绝对的安全,但是程序员编写程序太累,代码到处都是处理异常的代码。

4.异常的处理方式

  1. 第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级
  2. 第二种方式:使用try…catch语句进行异常的捕捉

    举例:
    我是某集团的一个销售员,因为我的失误,导致公司损失了1000元,“损失1000元”这可以看做是一个异常发生了,我有两种处理方式:
    第一种方式:我把这件事情告诉了我的领导【异常上抛】
    第二种方式:我自己掏腰包把这个钱补上【异常的捕捉】
  • 异常发生之后,如果我选择了上抛,抛给了我的调用者,调用者需要对这个异常继续处理,那么调用者处理这个异常同样有两种处理方式
  • java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续向上抛,抛给了调用者JVM,JVM知道这个异常发生,只有一个结果,终止java程序的执行
  • 只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行
  • try语句块中的某一行出现异常,该行后面的代码不会执行,try…catch捕捉异常之后,后续代码可以执行
  • 如果希望调用者来处理,选择throws上报

4.1 运行时异常举例

ArithmeticException 继承 RuntimeException,属于运行时异常,在编写程序阶段不需要对这种异常进行预先的处理

package exception;

public class ExceptionTest03 {
    public static void main(String[] args) {

        /*程序执行到此处发生了ArithmeticException异常,
        底层new了一个ArithmeticException异常对象,
        然后抛出了,由于是main方法调用了100 / 0,
        所以这个异常ArithmeticException抛给了main方法,
        main方法没有处理,将这个异常自动抛给了JVM,
        JVM最终终止程序的执行。
        */
        System.out.println(100 / 0);

        //这里没有输出,没有执行
        System.out.println("hello world!");
    }
}

4.2 编译时异常举例

以下代码报错的原因:
因为doSome()方法声明位置上使用了:throws ClassNotFoundException,而ClassNotFoundException是编写代码时异常,没有处理,编译器就报错

package exception;

public class ExceptionTest04 {
    public static void main(String[] args) {

        //main方法中调用doSome()方法
        //因为doSome()方法声明位置上有:throws ClassNotFoundException
        //我们在调用doSome()方法的时候必须对这种异常进行预先的处理
        //如果不处理,编译器就报错
        //编译器报错信息:Unhandled exception: java.lang.ClassNotFoundException
        doSome();
    }

    /**
     * doSome()方法在方法声明的位置上使用了:throws ClassNotFoundException
     * 这个代码表示doSome()方法在执行过程中,有可能会出现ClassNotFoundException异常
     * 叫做类没找到异常,这个异常直接父类是:Exception 所以ClassNotFoundException属于编译时异常
     * @throws ClassNotFoundException
     */
    public static void doSome() throws ClassNotFoundException{
        System.out.println("doSome!!!");
    }
}

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

package exception;

public class ExceptionTest05 {
    public static void main(String[] args) throws ClassNotFoundException {
        
        doSome();
    }
    
    public static void doSome() throws ClassNotFoundException{
        System.out.println("doSome!!!");
    }
}

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

package exception;

public class ExceptionTest05 {
    public static void main(String[] args) {

        try {
            doSome();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    
    public static void doSome() throws ClassNotFoundException{
        System.out.println("doSome!!!");
    }
}

4.3 处理异常的第一种方式:throws

在方法声明的位置上使用throws关键字抛出,谁调用这个方法,就抛给谁,抛给调用者来处理
处理异常的态度:上报

package exception;

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

public class ExceptionTest06 {
    public static void main(String[] args) throws FileNotFoundException {
        System.out.println("main begin");
        m1();
        System.out.println("main over");
    }

    private static void m1() throws FileNotFoundException {
        System.out.println("m1 begin");
        m2();
        System.out.println("m1 over");
    }

    //private static void m2() throw ClassCastException{   //抛别的不行,抛ClassCastException说明还是没有对FileNotFoundException处理
    //private static void m2() throws IOException { //抛出FileNotFoundException的父对象IOException是可以的,IOException包括FileNotFoundException
    //private static void m2() throws Exception { //可以,Exception包括所有的异常
    //private static void m2() throws ClassCastException,FileNotFoundException {//throws后面也可以写多个异常,可以使用逗号隔开
    private static void m2() throws FileNotFoundException {
        System.out.println("m2 begin");
        //编译器报错:m3()方法声明位置上有:throws FileNotFoundException
        //这里调用m3()方法没有对异常进行预处理,所以编译报错
        //m3();


        m3();
        System.out.println("m2 over");
    }

    private static void m3() throws FileNotFoundException {

        //调用SUN jdk中某个类的构造方法,后期IO流会讲
        //功能:创建一个输入流对象,该流指向一个文件
        /*报错原因:
        *  第一:这里调用了一个构造方法:FileInputStream(String name)
        *  第二:这个构造方法的声明位置上有:throws FileNotFoundException
        *  第三:通过类的继承结果看到:FileNotFoundException父类是IOException,IOException的父类是Exception
        *  最终得知:FileNotFoundException是编译时异常
        *
        *  错误原因:编译时异常要求程序员编写程序阶段必须对它进行处理,不处理编译器就报错
        * */
        //new FileInputStream("C:\\Users\\keith\\1.txt");

        new FileInputStream("C:\\Users\\keith\\1.txt");
    }
}

总结:一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM,JVM只有终止,异常处理机制的作用就是增强程序的健壮性,所以一般main方法中的异常建议使用try…catch进行捕捉,main就不要继续上抛了。

4.4 处理异常的第二种方式:try…catch

使用try…catch语句对异常进行捕捉
这个异常不会上报(上抛),自己把这个事儿处理了

package exception;

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

public class ExceptionTest06 {
    public static void main(String[] args) {
        System.out.println("main begin");
        try {
            //try 尝试
            m1();
        } catch (FileNotFoundException e) {//catch后面的好像一个方法的形参
            //这个分支中可以使用e引用,e引用保存的内存地址是那个new出来异常对象的内存地址
            //catch是捕捉异常之后走的分支
            System.out.println("文件不存在,可能路径错误,也可能该文件被删除了!");
        }

        //try..catch把异常抓住之后,这里代码会继续执行
        System.out.println("main over");
    }

    private static void m1() throws FileNotFoundException {
        System.out.println("m1 begin");
        m2();
        System.out.println("m1 over");
    }

    private static void m2() throws FileNotFoundException {
        System.out.println("m2 begin");
        m3();
        System.out.println("m2 over");
    }

    private static void m3() throws FileNotFoundException {
        new FileInputStream("C:\\Users\\keith\\1.txt");
    }
}

当路径正确的时候,运行结果

在这里插入图片描述
当路径不正确的时候,运行结果

在这里插入图片描述

4.5 深入 try…catch

  1. catch后面的小括号中的类型可以是具体的异常类型,也可以是异常类型的父类型
  2. catch可以写多个,建议catch的时候,精确的一个一个处理,这样有利于程序的调试
  3. catch写多个的时候,从上到下,必须遵守从小到大

测试实验一

package exception;

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

public class ExceptionTest07 {
    public static void main(String[] args) {

        try {
            FileInputStream fis = new FileInputStream("C:\\Users\\keith\\1.txt");
            System.out.println("以上出现异常,这里无法执行!!!");
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在!");
        }

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

当路径正确的时候,运行结果

在这里插入图片描述
当路径不正确的时候,运行结果

在这里插入图片描述
测试实验二

package exception;

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

public class ExceptionTest07 {
    public static void main(String[] args) {

        try {
            FileInputStream fis = new FileInputStream("C:\\Users\\keith\\12.txt");
        } catch (IOException e) {//多态:IOException e = new FileNotFoundException();
            System.out.println("文件不存在!");
        }

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

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

public class ExceptionTest07 {
    public static void main(String[] args) {

        try {
            FileInputStream fis = new FileInputStream("C:\\Users\\keith\\12.txt");
        } catch (Exception e) {//多态:Exception e = new FileNotFoundException();
            System.out.println("文件不存在!");
        }

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

测试实验三

package exception;

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

public class ExceptionTest07 {
    public static void main(String[] args) {

        try {
            //创建输入流
            FileInputStream fis = new FileInputStream("C:\\Users\\keith\\12.txt");

            //读文件
            fis.read();
        } catch (FileNotFoundException e) {//多态:IOException e = new FileNotFoundException();
            System.out.println("文件不存在!");
        }catch (IOException e){
            System.out.println("读取失败!");
        }

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

测试实验四
JDK8的新特性

package exception;

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

public class ExceptionTest07 {
    public static void main(String[] args) {

        try {
            //创建输入流
            FileInputStream fis = new FileInputStream("C:\\Users\\keith\\12.txt");

            System.out.println(100 / 0);//这个异常是运行时异常,编写程序的时候可以处理,也可以不处理
        } catch (FileNotFoundException | ArithmeticException | NullPointerException e) {
            System.out.println("文件不存在?数学异常?空指针异常?");

        }
    }
}

5.异常对象的常用方法

5.1 getMessage方法

获取异常简单的描述信息

String msg = exception.getMessage();

演示代码

package exception;

public class ExceptionTest08 {
    public static void main(String[] args) {

        //这里只是new了异常对象,但是没有将异常对象抛出,JVM会认为这是一个普通的java对象
        NullPointerException e = new NullPointerException("空指针异常!!!");

        //获取异常简单描述信息:这个信息实际上就是构造方法上面String参数
        String msg = e.getMessage();
        
        System.out.println(msg);//输出为:空指针异常!!!
    }
}

5.2 printStackTrace()方法

打印异常追踪的堆栈信息:

exception.printStackTrace();

演示代码一

package exception;

public class ExceptionTest08 {
    public static void main(String[] args) {

        //这里只是new了异常对象,但是没有将异常对象抛出,JVM会认为这是一个普通的java对象
        NullPointerException e = new NullPointerException("空指针异常!!!");

        //打印异常堆栈信息
        //java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的
        e.printStackTrace();

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

运行结果

在这里插入图片描述
演示代码二

package exception;

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

public class ExceptionTest09 {
    public static void main(String[] args) {
        try {
            m1();
        } catch (FileNotFoundException e) {
            //打印异常堆栈追踪信息
            //在实际开发中,建议使用这个,养成好习惯
            e.printStackTrace();
        }

        //这里程序不耽误执行,很健壮【服务器不会因为遇到异常而宕机/死机】
        System.out.println("hello world!");
    }

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

    private static void m2() throws FileNotFoundException {
        m3();
    }

    private static void m3() throws FileNotFoundException {
        new FileInputStream("C:\\Users\\keith\\12.txt");
    }
}

运行结果

在这里插入图片描述

6.查看异常的追踪信息

  1. 从上往下一行一行看
  2. SUN写的代码就不用看了,主要的问题出现在自己编写的代码上【看包名判断是不是SUN写的】

演示
在这里插入图片描述
注:第一行是异常信息,中间的是SUN写的,下面的是自己的错误部分!

7.finally关键字

  1. finally子句属于try…catch语句中
  2. 在finally子句中的代码时最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。
  3. finally子句必须和try一起使用,不能单独编写
  4. 通常在finally语句块中完成资源的释放/关闭,因为finally中的代码比较有保障,即使try语句块中的代码出现异常,finally中代码也会正常执行

7.1 代码实训一

package exception;

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

public class ExceptionTest10 {
    public static void main(String[] args) {

        //声明位置放在try外面,这样在finally中才能用
        FileInputStream fis = null;

        try {
            //创建输入流对象
            fis = new FileInputStream("C:\\Users\\keith\\12.txt");
            //开始读文件...

            String s = null;
            //这里一定会出现空指针异常!
            s.toString();

            //流使用完需要关闭,因为流时占用资源的
            //即使以上程序出现异常,流也必须要关闭!
            //放在这里有可能流关不了
            //fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }catch (NullPointerException e){
            e.printStackTrace();
        }finally {
            //流的关闭放在这里比较保险
            //finally中的代码是一定会执行的
            //即使try中出现了异常
            if (fis != null) {//避免空指针异常
                try {
                    fis.close();//close()方法有异常,采用捕捉的方式
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

7.2 代码实训二

  1. try和finally,没有catch也是可以使用的,即try和finally可以联合使用
  2. try不能单独使用
  3. 放在finally语句块中的代码是一定会执行的

以下代码执行顺序:

  • 先执行try
  • 再执行finally
  • 最后执行return(return语句只要执行,方法必然结束)
package exception;

public class ExceptionTest11 {
    public static void main(String[] args) {

        try {
            System.out.println("try");
            return;
        }finally {
            System.out.println("finally");
        }
        //这里不能写语句,因为这个代码是无法执行到的
        //System.out.println("hello");
    }
}

运行结果

在这里插入图片描述

7.3 代码实训三

退出JVM之后,finally语句中的代码就不执行了

package exception;

public class ExceptionTest12 {
    public static void main(String[] args) {
        try {
            System.out.println("try");

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

7.4 finally面试题

package exception;

public class ExceptionTest13 {
    public static void main(String[] args) {
        int result = m();
        System.out.println(result);//输出为:100
    }

    /*
    java语法规则:
    1.方法体中的代码必须遵循自上而下顺序依次逐行执行
    2.return语句一旦执行,整个方法必须结束
     */
    private static int m() {
        int i = 100;
        try{
            //这行代码出现在int i = 100;下面,所以最终结果必须是返回100
            //return语句还必须保证是最后执行的,一旦执行,整个方法结束
            return i;
        }finally {
            i++;
        }
    }
}

m()函数反编译之后效果

 private static int m() {
        int i = 100;
        int j = i;
        i++;
        return i;
    }

8.final、finalize和finally区别

final关键字final修饰的类无法继承;final修饰的方法无法覆盖;final修饰的变量不能重新赋值
finally关键字和try一起联合使用;finally语句块中的代码时必须执行的
finalize标识符是一个Object类中的方法名,整个方法是由垃圾回收器GC负责调用
package exception;

public class ExceptionTest14 {
    public static void main(String[] args) {

        //final是一个关键字,表示最终的,不变的
        final int i = 100;
        //i = 200;


        //finally也是一个关键字,和try联合使用,使用在异常处理机制中
        //在finally语句块中的代码是一定会执行的
        try{

        }finally {
            System.out.println("finally");
        }


        //finalize()是Object类中的一个方法,作为方法名出现
        //所以finalize是标识符
        //finalize()方法是JVM的GC垃圾回收器负责调用
        Object obj;
    }
}

9.如何自定义异常类

SUN提供的JDK内置的异常肯定是不够用的,在实际的开发中,有很多业务,这些业务出现异常之后,JDK中都是没有的, 和业务挂钩的,那么异常类可以由程序员自己定义。

Java中自定义异常两步骤

  1. 编写一个类继承Exception或者RuntimeException
  2. 提供两个构造方法,一个无参数的,一个带有String参数的

异常类

package exception;

public class MyException extends Exception {//编译时异常

    public MyException(){

    }

    public MyException(String s){

        super(s);
    }
}


/*
public class MyException extends RuntimeException {//运行时异常

}*/

测试类

package exception;

public class ExceptionTest15 {
    public static void main(String[] args) {

        //创建异常对(只new了异常对象,并没有手动抛出)
        MyException e = new MyException("用户名不能为空!");

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

        //获取异常简单描述信息
        String msg = e.getMessage();
        System.out.println(msg);
    }
}

运行结果

在这里插入图片描述

10.异常在实际开发中的作用

异常类
栈操作异常

package exception;

public class MyStackOperationException extends Exception {
    public MyStackOperationException() {
    }

    public MyStackOperationException(String message) {
        super(message);
    }
}

package exception;

public class MyStack {

    //向栈中存储元素,这里使用一维数组模拟,存到栈中,就表示存储到数组中
    //Object类型数组可以存储java中的任何引用类型的数据(一般对象的超级父类就是Object)
    //String父类也是Object,但是在java中有优待,不需要new也是一个对象
    //private Object[] elements = new Object[10]; 也可以这样进行初始化 //等号在构造方法执行的时候赋值
    private Object[] elements;

    //栈帧 永远指向栈顶元素
    private int index = -1;

    //无参构造方法
    public MyStack() {
        //默认初始化栈容量10
        this.elements = new Object[10];
    }

    //压栈
    public void push(Object obj) throws MyStackOperationException {

        if (this.index >= this.elements.length - 1){
            /*System.out.println("压栈失败,栈已满!");
            return;*/

            //创建异常对象
            MyStackOperationException e = new MyStackOperationException("压栈失败,栈已满!");

            //手动将异常抛出去
            //这里捕捉没有意义,自己new一个异常,自己捉没有意义。栈已满这个信息需要传递出去
            throw e;

            //合并上面的  手动抛出异常
            //throw new MyStackOperationException("压栈失败,栈已满!");
        }

        //程序能够走到这里,说明栈没满
        //向栈中加1个元素,栈帧向上移动一个位置
        this.index++;
        this.elements[index] = obj;
        //上面两行可以等价于
        //this.elements[++index] = obj;

        //obj是一个引用,自动调用引用的toString()方法 如:obj.toString()
        System.out.println("压栈"+ obj + "元素成功,栈帧指向 " + this.index);
    }

    //弹栈
    public void pop() throws MyStackOperationException {
        if (this.index < 0){
            /*System.out.println("栈已空,弹栈失败!");
            return;*/

            throw new MyStackOperationException("栈已空,弹栈失败!");
        }

        //程序能够走到这里,说明栈没空
        System.out.println("弹栈"+ this.elements[this.index] + "元素成功 ");
        //栈帧向下移动一位
        this.index--;
        System.out.println(" 栈帧指向 " + this.index);

    }
    //set和get方法也许用不上,但是必须写,这是规矩
    //封装:第一步:属性私有化 第二步:对外提供set和get方法
    public Object[] getElements() {
        return elements;
    }

    public void setElements(Object[] elements) {
        this.elements = elements;
    }
}

自定义测试类

package exception;

//测试改良后的MyStack
public class ExceptionTest16 {
    public static void main(String[] args) {

        //创建栈对象
        MyStack stack = new MyStack();

        //压栈
        try {
            stack.push(new Object());
            stack.push(new Object());
            stack.push(new Object());
            stack.push(new Object());
            stack.push(new Object());
            stack.push(new Object());
            stack.push(new Object());
            stack.push(new Object());
            stack.push(new Object());
            stack.push(new Object());
            //这里栈满了
            stack.push(new Object());
        } catch (MyStackOperationException e) {

            //输出异常的简单信息
            System.out.println(e.getMessage());
        }

        //弹栈
        try {
            stack.pop();
            stack.pop();
            stack.pop();
            stack.pop();
            stack.pop();
            stack.pop();
            stack.pop();
            stack.pop();
            stack.pop();
            stack.pop();
            stack.pop();
            //弹栈失败
            stack.pop();
        } catch (MyStackOperationException e) {

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

运行结果

在这里插入图片描述

11.异常和方法覆盖

在方法覆盖内容部分,有一个遗留问题:
重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少

package exception;

class Animal{
    public void doSome(){

    }

    public void doOther() throws Exception{

    }
}

class Cat extends Animal{

    //错误
    /*public void doSome() throws Exception{

    }*/

    //编译正常
    public void doSome() throws RuntimeException{

    }

    //编译正常
   /* public void doOther(){

    }*/

    /*//编译正常
    public void doOther() throws Exception{

    }*/
    
    //编译正常
    public void doOther() throws NullPointerException{

    }
}

总结异常中的关键字
异常捕捉:try、catch、finally
throws:在方法声明位置上使用,表示上报异常信息给调用者
throw:手动抛出异常!

12.异常作业

编写程序模拟用户注册:

  1. 程序开始执行时,提示用户输入“用户名”和“密码”信息
  2. 输入信息之后,后台java程序模拟用户注册
  3. 注册时用户名要求长度在[6-14]之间,小于或者大于都表示异常

注意:完成注册的方法放到一个单独的类中,异常类自定义即可。

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

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

自定义异常类

package exception.homework;

public class IllegalNameException extends Exception{
    public IllegalNameException() {
    }

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

用户业务类
处理用户相关的业务:例如登录、注册等功能。

package exception.homework;

public class UserService {


    /**
     * 用户注册
     * @param username 用户名
     * @param password 密码
     * @throws IllegalNameException 当用户名为Null,或者用户名长度小于6,大于14,会出现该异常
     */
    public void register(String username,String password) throws IllegalNameException {

        /*//引用等于null的这个判断最好放到所有条件的最前面
        if (username == null || username.length() < 6 || username.length() > 14){
        }*/

        //username == null 不如写成: null == username  避免手误写成:username = null 将空值赋给变量
        if (null == username || username.length() < 6 || username.length() > 14){

            throw  new IllegalNameException("用户名不合法,长度必须在[6-14]之间!");
        }

        //程序执行到此处说明用户名合法
        System.out.println("注册成功,欢迎[" + username + "]");

    }
}

测试类

package exception.homework;

public class Test {
    public static void main(String[] args) {

        //创建UserService对象
        UserService userService = new UserService();

        //用户名和密码就不再从控制台接收了


        try {
            userService.register("zhangsan","123");
        } catch (IllegalNameException e) {
            System.out.println(e.getMessage());
        }
    }
}

运行结果

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值