【Java进阶学习 第十篇】递归和异常

递归

方法直接或者间接调用本身


案例1 递归求5的阶乘

java 复制代码
public class RecursionDemo1 {
    public static void main(String[] args) {
        //递归 方法直接或间接调用本身
        System.out.println(calculateMulti(5));
    }

    private static int calculateMulti(int i) {
        if(i == 1)
        {
            return 1;
        }
        return i * calculateMulti(i-1);
        //120
    }
}

递归出口条件:1的阶乘是1,求5的阶乘其实下一步是5乘4的阶乘,而4的阶乘就可以用阶乘计算方法(i-1)代替

栈内存示意图

递归调用jc方法,到最后一次调用jc方法的时候,将结果return1回给上一次调用的jc(num-1),最后就是2*1;3*2;4*6;5*24,retun给主方法120,程序运行结束


案例2 使用递归求1到n的和

用户输入n------递归调用求和的方法

java 复制代码
public class RecursionDemo2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入您想从1求和到多少:");
        int n = sc.nextInt();
        System.out.println(sum(n));

    }
    public static int sum(int n) {
        if(n==1)
        {
            return 1;
        }
        return sum(n-1)+n;
    }
}

出口定义为n==1时返回1,所以从n开始调用方法,只要n大于1,返回值就是n+加上方法(n-1)


案例3 不死神兔

递归方法调用参数是月份,假如说n是1和2就没有新兔子,就是一对,所以总数不变就为1

假设说递归调用方法为rabbit,那么rabbit(1)和rabbit(2)都是==1的,从第三月开始,rabbit都会产生新兔子,总兔子对数依次是1,1,2,3,5,8,可以发现从第三个月开始,是前两个月的和,3=2+1,5=2+3,那么rabbit3以上就可以用rabbit(i-2)+rabbit(i-1)进行表示并进行递归

java 复制代码
public class RecursionDmoe3 {
    public static void main(String[] args) {
        System.out.println(rabbit(20));
    }
    public static int rabbit(int n) {
        if(n == 1) {
            return 1;
        }
        if(n == 2) {
            return 1;
        }
        else {
            return rabbit(n - 1) + rabbit(n - 2);
        }
        //6765
    }
}

递归主要是找规律+定义好递归出口,不要死循环


案例4 猴子吃桃

递归出口条件就是n=10的时候,只剩下一个桃子,所以输入应为从哪一天到第十天

java 复制代码
public class RecurisionDemo4
{
    public static void main(String[] args)
    {
        System.out.println(peach(1));
    }

    public static int peach(int n)
    {
        if (n == 10)
        {
            return 1;
        }
        else {
            return (peach(n+1)+1)*2;
        }
    }
}

除了第十天返回值为1之外,之前的每一天桃子的数量都是下一天桃子的数量先+1再×2


异常

程序在编译或者运行的时候出现的错误

异常体系

Error为严重级别问题,常见有栈内存溢出和堆内存溢出

我们常见的异常都为Exception类

其中分为RuntimeException及子类------运行时异常 和除RuntimeException之外的所有异常------编译时异常

编译时异常主要是提醒作用,虽然语法没有问题,但是输入参数容易出现错误。


异常的默认处理流程

  1. 出现异常,创建异常对象
  2. 异常从方法中出现的点抛出给调用者,调用者抛出给JVM虚拟机
  3. 虚拟机接收到异常对象之后,控制台直接输出异常信息数据
  4. java程序终止运行

异常处理方法

try------catch捕获异常

异常对象可以被捕获,不会抛出给虚拟机,java可以继续运行

java 复制代码
public class exceptionDemo1 {
    public static void main(String[] args) {
        System.out.println("开始");
        try {
            System.out.println(10 / 0);
        }catch (ArithmeticException e){//ArithmeticException e=new ArithmeticException()
            System.out.println("捕获除0的运算异常");
        }
        System.out.println("结束");
    }
//    开始
//    捕获除0的运算异常
//    结束
}

如果出现异常则catch会创建对象捕获try中new的异常对象,如果没有异常发生catch不工作。

java 复制代码
public class exceptionDemo1 {
    public static void main(String[] args) {
        System.out.println("开始");
        try {
            int[] arr = null;
            System.out.println(arr[8]);
            System.out.println(10 / 0);
        }catch (ArithmeticException e){//ArithmeticException e=new ArithmeticException()
            System.out.println("捕获除0的运算异常");
        }catch (NullPointerException e){
            System.out.println("捕获空指针异常");
        }
        System.out.println("结束");
    }
//    开始
//    捕获空指针异常
//    结束

可以捕获多个异常,如果还有其他异常可以使用父类引用Exception e捕获其他异常


需求 录入student信息

在输入年龄的时候,可以用Integer的parseInt方法将字符串转为整数,但是这里的输入可能出现异常,所以可以用try------catch加while循环的方法进行代码的维护

java 复制代码
public class tryCatchDemo {
    public static void main(String[] args) {
        Student stu=new Student();

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入学生姓名");
        String name = sc.nextLine();

        System.out.println("请输入学生年龄");
        int age= 0;
        while (true){
            try {
                age = Integer.parseInt(sc.nextLine());
                break;
            } catch (NumberFormatException e) {
                System.out.println("年龄输入有误,请输入整数年龄");
            }
        }
        stu.setName(name);
        stu.setAge(age);

        System.out.println(stu);
    }
}

throw和throws抛出异常

throw用在方法中,后面跟着异常对象,用于抛出异常对象

throws用在方法名后面,起到声明作用

如果异常对象为编译时异常,必须使用throws声明;如果是运行时异常,则不需要写throws

java 复制代码
    public void setAge(int age) {
        if (age < 0 || age > 100) {
            throw new IllegalArgumentException("Age must be between 0 and 100");
        }
        else{
            this.age = age;
        }
    }
java 复制代码
    public void setAge(int age)throws Exception {
        if (age < 0 || age > 100) {
            throw new Exception("Age must be between 0 and 100");
        }
        else{
            this.age = age;
        }
    }

throw可以暴露异常,也可以在暴露之后用try------catch进行捕获


自定义异常

如果想自定义编译时异常,创建一个类继承Exception

如果想自定义运行时异常,创建一个类继承RunTimeException

初始化可以让父类帮忙,比如说刚才的学生年龄异常,就可以写为

java 复制代码
public class StudentException extends RuntimeException {
    public StudentException() {
        
    }
    public StudentException(String message) {
        super(message);
    }
}
java 复制代码
    public void setAge(int age) {
        if (age < 0 || age > 100) {
            throw new StudentException("Age must be between 0 and 100");
        }
        else{
            this.age = age;
        }
    }

自定义异常能够正常将异常抛出

相关推荐
一只小青团3 小时前
Python之面向对象和类
java·开发语言
qq_529835353 小时前
ThreadLocal内存泄漏 强引用vs弱引用
java·开发语言·jvm
落笔画忧愁e3 小时前
扣子Coze飞书多维表插件添加数据记录
java·服务器·飞书
不太可爱的叶某人4 小时前
【学习笔记】MySQL技术内幕InnoDB存储引擎——第5章 索引与算法
笔记·学习·mysql
岁岁岁平安4 小时前
Redis基础学习(五大值数据类型的常用操作命令)
数据库·redis·学习·redis list·redis hash·redis set·redis string
知识分享小能手5 小时前
Vue3 学习教程,从入门到精通,使用 VSCode 开发 Vue3 的详细指南(3)
前端·javascript·vue.js·学习·前端框架·vue·vue3
秋千码途6 小时前
小架构step系列08:logback.xml的配置
xml·java·logback
飞翔的佩奇6 小时前
Java项目:基于SSM框架实现的旅游协会管理系统【ssm+B/S架构+源码+数据库+毕业论文】
java·数据库·mysql·毕业设计·ssm·旅游·jsp
pay4fun6 小时前
2048-控制台版本
c++·学习
时来天地皆同力.6 小时前
Java面试基础:概念
java·开发语言·jvm