一、递归
1.递归介绍
方法直接或者间接调用本身
//直接调用自身
public static void methodA() {
methodA();
}
//间接调用自身
public static void methodA() {
methodB();
}
public static void methodB() {
methodA();
}
一些算法的实现, 都需要使用递归
注:递归如果没有控制好终止,会出现递归死循环,导致栈内存溢出现象
2.递归使用
例1:使用递归求5的阶乘
分析:5! = 5 * 4! , 4! =4 * 3! , 3! = 3 * 2! , 2! = 2 * 1! , 1! = 1
public static void main(String[] args) {
int result = jc(5);
System.out.println(result);
}
public static int jc(int num) {
if (num == 1) {//递归的出口
return 1;
} else {
return num * jc(num - 1);//循环调用
}
}
例2:使用递归求1~n的和
分析:1 ~ 5 的和 5 += (1~4的和); 1 ~ 4 的和 4 += (1~3的和); 1 ~ 3 的和 3 += (1~2
的和); 1 ~ 2 的和 2 += (1~1的和); 1 ~ 1 的和 结果就是1;
public static void main(String[] args) {
int sum = getSum(5);
System.out.println(sum);
}
public static int getSum(int n) {
if (n == 1) {//递归的出口
return 1;
} else {
return n += getSum(n - 1);//循环调用
}
}
例3:不死兔子 (斐波那契数列)
有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每
个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?
分析:第1个月:1 ,第2个月:1 ,第3个月:2 ,第4个月:3……
1 1 2 3 5 8 13……
public static void main(String[] args) {
int result = get(20);
System.out.println(result);
}
public static int get(int month) {
if (month == 1 || month == 2) {//递归的出口
return 1;
} else {
return get(month - 2) + get(month - 1);//循环调用
}
}
二、异常
1.异常介绍
指的是程序在编译或执行过程中,出现的非正常的情况,但语法错误不是异常。
异常体系:
Error 严重级别问题
常见的 : 栈内存溢出 (StackOverflowError) 堆内存溢出 (OutOfMemoryError)
Exception:
RuntimeException 及其子类:运行时异常
每个异常都是一个类,在API中可查。
阅读异常信息 : 从下往上看
1. 找异常错误位置
2. 异常名称
3. 异常原因
常见异常运行时异常:
数组索引越界异常: ArrayIndexOutOfBoundsException
空指针异常 : NullPointerException
数学操作异常:ArithmeticException
类型转换异常:ClassCastException
数字转换异常: NumberFormatException
除RuntimeException 之外所有的异常:编译时异常
编译阶段就出现的错误 主要起到提醒作用,需要在运行之前, 给出解决方案
2.异常处理方式
异常的默认处理流程
① 虚拟机会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException
② 异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机
③ 虚拟机接收到异常对象后,先在控制台直接输出异常信息数据
④ 终止 Java 程序的运行
⑤ 后续代码没有机会执行了,因为程序终止
异常处理方式 try...catch...
能够将抛出的异常对象捕获,然后执行异常的处理方案
好处:程序可以继续往下执行
try { 可能会出现异常的代码 }
catch(异常类型1 变量) { 处理异常的方案 }
catch(异常类型2 变量) { 处理异常的方案 }
注:如果使用多个catch, 最大的异常需要放在最后
try {
System.out.println(10 / 0);
} catch (ArithmeticException e) {
String message = e.getMessage();
//getMessage()返回的是异常原因,printStackTrace()展示完整的异常错误信息
System.out.println(message);
}
异常处理方式 throws 抛出
throws:用在方法上,作用是声明,声明这个方法中有可能会出现异常
格式:
public void method() throws 异常1,异常2,异常3... { }
例:
注:子类重写父类方法时, 不能抛出父类没有的异常, 或者比父类更大的异常
throw 和 throws 的区别
throw : 用在方法中, 后面跟的是异常对象, 其作用是抛出异常对象
throws : 用在方法名后面, 起到声明作用
声明此方法中存在异常, 调用者需要进行处理
细节 : 抛出的异常对象如果是编译时异常, 必须使用 throws 声明
例:封装为 Student 对象,键盘录入学生的姓名和年龄,要保证年龄的正确
构造方法:
public void setAge(int age) {
if(age >= 0 && age <= 120){
this.age = age;
} else {
// 错误的年龄
throw new StudentAgeException("年龄范围有误, 需要0~120之间的
年龄");
}
}
3.自定义异常
Java无法为这个世界上全部的问题提供异常类。
如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类了
1、自定义编译时异常
定义一个异常类继承Exception. 重写构造器
2、自定义运行时异常
定义一个异常类继承RuntimeException. 重写构造器。