欢迎光临散文网 会员登陆 & 注册

Java笔记--递归、异常

2023-11-01 21:04 作者:爪哇岛江户川  | 我要投稿

一、递归

方法直接或间接的调用自身。

注意事项:递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出现象。

一些算法题的实现,都需要使用递归。

我们来做一个小案例:假设我们要求出5的阶乘,我们可以自定义一个方法去求阶乘,然后用方法去调用方法。

这段代码在栈内存中是这样的:

return是把结果返回给调用者的。


二、异常

异常:指的是程序在编译或执行过程中,出现的非正常的情况

例如我们之前遇到的索引越界异常、类型转换异常、空指针异常等。

Java中所有的异常都是类。

异常的体系结构:

我们主要来了解Exception

<1>RuntimeException 运行时异常

编译通过了,但是运行报错了,例如10/0编译不会报错,但是运行时会报错。

<2>除了RuntimeException之外的其它异常

编译时出现问题,例如int age = Integer.parseInt(sc.next());这串代码是将字符串类型转为int类型的,加入我们输入的是12可以正常赋值,但如果输入abc,程序将会出现异常。

三、异常处理的两种方式

(1)默认的处理方式:向上抛出

我们在现在故意写了一个会出现异常的代码,然后去运行它。

我们可以看到程序首先打印了一个开始,然后出现异常,报错信息从下往上看,在第9行出现了异常,我们在第9行调用了method方法,再往上看,第14行出现了异常,而第14行就是方法中我们用10/0的代码。再继续往上看,异常信息是ArithmeticException。我们前面说过,Java中的异常都是类,类是可以用来new对象的。

当我们第十四行出现异常时,Java会自动帮我们创建一个异常对象的,new ArithmeticException( );

就好比程序中现在有一颗雷,这颗雷在Java中的默认处理方式就是向上抛出,上指的就是上一级或者说调用者。在method方法中出现的问题,谁调的method方法,main方法,谁掉的main方法,JVM,谁调用的JVM,程序员,所以Java将异常的位置、原因都在控制台给程序员展示出来,然后强制将我们的程序关闭。


(2)两种异常处理方式:

<1>try...catch捕获异常

我们用一个例题来理解try...catch捕获异常是怎么处理的

程序跑起来之后,创建了一个运算异常的对象,然后被catch捕获了

假如我们同时有多个异常,可以多几个catch来处理

可能有人就会觉得,如果我们在编写代码的时候,同时出现了很多个异常,难道要同时写很多个catch吗?

其实我们可以只用一个catch,然后在后面的括号里写Exception,因为Exception是编译时异常和运行时异常的父类,这样就可以捕获所有的异常。

但是这种捕获异常的方式只能用同一个处理方案,而多个catch可以精准捕获使用不同的处理方案。

<2>throws抛出异常

假如我们写一个方法将日期格式化,在调用parse方法时可能会出现异常,我们前面提到过,如果代码中可能会出现异常,我们得在运行之前给它一个处理方案。

当我们使用ALT+回车后选择抛出异常处理方式后,发现方法名后面多了一句代码throws ParseException。throws是异常的声明,说明这个方法中可能存在异常,parseException是异常的类型。

当我们在主方法中调用method方法的时候,还是会报错,因为method方法中已经声明了可能会出现异常,这个问题我们要不要在main方法中处理?如果我们继续选择throws抛出异常,main方法后面也会多出一个同样的声明throws ParseException,然后我们运行试试看是如何处理的:

我们发现还是会将异常信息打印在控制台上然后强制终止程序的运行。其实这种方式并没有将异常处理掉,只是起到了声明作用。

同样的,如果出现了多个异常的话,也可以选择直接声明异常的父类。

(3)两种异常的处理方式该如何选择?

创建一个学生类,定义年龄,然后提供set方法,如果有人来调用set方法输入年龄时时,输入了错误的数,例如-23,我们应该将问题暴露给调用者。

我们可以直接创建一个异常对象,就像制造一个炸弹一样,当调用者传入了错误的数据,我们应该将异常抛出,将炸弹直接扔给他,让他去处理。throw抛出异常 new Exception是创建异常对象。

我们可以看到代码依旧是会报错的,因为我们还得声明一下我们这个代码中可能会出现异常,所以需要在set方法后面声明可能会出现的异常。

然后我们回到main方法中,调用set方法的地方依旧会报错,因为前面我们声明了一个可能出现的异常,并且将之抛给了调用者,所以main方法中就接到了这个炸弹,所以我们有两种处理方式,要么抛出异常,要么就try...catch捕获异常,如果我们抛出异常,运行代码还是展示出错误信息,所以我们选择捕获异常,然后我们再添加一句catch。

当setage出现异常的时候,下面的catch就会将异常捕获,格式有错的异常会被上面的catch拦截,范围有错的异常会被下面的catch拦截,直到age成功赋值走到break才跳出循环。


四、自定义异常

在上面的例子中,虽然我们成功将异常捕获但是我们在catch中异常用的是exception类,这个类范围太大了,不能做到精准捕获,但是异常类中又没有我们需要的类,这个时候我们就可以自定义异常类然后让它去继承父类。

但是,还要往类里面加入构造方法,一般只需要一个空参的和一个带String字符串的构造方法。

所以我们在学生类中应该扔出的炸弹是我们自定义的炸弹,我的意思是将异常类改为我们自定义的类。


Java笔记--递归、异常的评论 (共 条)

分享到微博请遵守国家法律