【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;
        }
    }

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

相关推荐
明天不下雨(牛客同名)2 小时前
为什么 ThreadLocalMap 的 key 是弱引用 value是强引用
java·jvm·算法
多多*2 小时前
Java设计模式 简单工厂模式 工厂方法模式 抽象工厂模式 模版工厂模式 模式对比
java·linux·运维·服务器·stm32·单片机·嵌入式硬件
Qwertyuiop20163 小时前
搭建开源笔记平台:outline
笔记·开源
白夜易寒3 小时前
Docker学习之私有仓库(day10)
学习·docker·容器
淮北4943 小时前
ros调试工具foxglove使用指南三:在3d空间写写画画(Panel->3D ->Scene entity)
python·学习·3d·机器人
胡图蛋.4 小时前
Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?
java·spring boot·后端
牛马baby4 小时前
Java高频面试之并发编程-01
java·开发语言·面试
小小大侠客4 小时前
将eclipse中的web项目导入idea
java·eclipse·intellij-idea
不再幻想,脚踏实地4 小时前
MySQL(一)
java·数据库·mysql
吃海鲜的骆驼4 小时前
SpringBoot详细教程(持续更新中...)
java·spring boot·后端