异常
- 异常就是代表程序出现的问题
当一个方法出现问题,这个方法内部就会把这个问题的信息封装成一个异常对象,然后把这个异常对象抛给jvm虚拟机,jvm收到之后会先把出问题的程序先停下来,然后再把这个异常对象打印出来,里面会包含该问题的很多信息
例:
异常的体系
Error:代表的系统级别错误(属于严重问题),也就是说系统一旦出现问题,sun公司会把这些问题封装成Error对象给出来。说白了,Error是给sun公司自己用的,不是给我们程序员用的,因此我们开发人员不用管它
Exception:叫异常,它代表的才是我们程序可能出现的问题,所以,我们程序员通常会用Exception以及它的孩子来封装程序出现的问题
- 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时出现的异常(如:数组索引越界异常)
- 编译时异常:编译阶段就会出现错误提醒的。(如:日期解析异常)
运行时异常:
刚才举出的例子就是运行时异常:
还有典型的数组越界异常:
编译时异常:
当你写代码时就会通过报错强制提醒你这个方法很容易出问题,提醒你最好认真检查一下~如果不检查不处理,程序将会报错。可以通过try catch捕获可能出现的异常抛出去,也可以通过throws把异常抛给上一层(jvm虚拟机)处理,当然jvm也不知道怎么处理你的问题,只是帮你去用rty catch去环绕问题代码
try catch 捕获异常:
throws抛出异常:
自定义异常
- Java无法为这个世界上全部的问题都提供异常类来代表,如果企业自己的某种问题,想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
自定义异常的种类:
自定义运行时异常
自定义异常继承类:
public class AgeIllegalRuntimeException extends RuntimeException{ //运行时异常必须继承自RuntimeException
public AgeIllegalRuntimeException() {
}
public AgeIllegalRuntimeException(String message) {
super(message);
}
}
test:
public class 自定义异常 {
public static void main(String[] args) {
try { //用try catch捕获异常
SetAge(151); //非法值
System.out.println("底层执行成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("底层出现bug!");
}
}
private static void SetAge(int age) {
if(age >= 0 && age <= 150){
System.out.println("年龄设置成功");
}else{ //触发else说明age的值有问题不合法
//用一个异常对象封装这个问题
//用throw抛出去
throw new AgeIllegalRuntimeException("年龄异常,年龄为非法值(Age is illegal, your age is):"+age);
}
}
}
运行结果:
自定义编译时异常
public class AgeIllegalException extends Exception{ //编译时异常必须继承自Exception
public AgeIllegalException() {
}
public AgeIllegalException(String message) {
super(message);
}
}
test:
public class 自定义异常 {
public static void main(String[] args) {
try { //用try catch捕获异常或抛出异常,否则直接报错
SetAge(151); //非法值
System.out.println("底层执行成功!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("底层出现bug!");
}
}
private static void SetAge(int age) throws AgeIllegalException{
if(age >= 0 && age <= 150){
System.out.println("年龄设置成功");
}else{ //触发else说明age的值有问题不合法
//用一个异常对象封装这个问题
//用throw抛出去
//用throws用在方法上,抛出这个方法内部出现的异常
throw new AgeIllegalException("年龄异常,年龄为非法值(Age is illegal, your age is):"+age);
}
}
}
运行结果:
总结:自定义运行时异常和自定义编译时异常用法是非常相似的,不过在效果上自定义编译时异常会在编译时就提醒你处理
异常有什么作用?
- 异常是用来查询系统Bug的关键参考信息
- 异常可以作为方法内部的一种特殊返回值,以便通知上层调用者底层的执行情况
开发中关于异常的常见处理方式
1、捕获异常,记录异常并响应合适的信息给用户
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionTest2 {
public static void main(String[] args) throws ParseException{
try { //调用者捕获异常
test1();
} catch (Exception e) { //记录异常并响应合适的信息给用户
System.out.println("您当前的操作有问题");
e.printStackTrace();
}
}
//直接抛Exception就行了,不用抛具体异常
private static void test1() throws Exception{ //异常,抛给调用者
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse("2021-07-07 23:23:20");
System.out.println(d);
test2();
}
private static void test2() throws Exception{ //异常,抛给调用者
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse("2021-07-07 23:23");
System.out.println(d);
}
}
运行结果:
2、捕获异常,"尝试重新修复
import java.text.ParseException;
import java.util.Scanner;
public class ExceptionTest3 {
public static void main(String[] args) throws ParseException {
while (true) { //循环围住,直到成功执行
try {
System.out.println(getMoney());
break;
} catch (Exception e) {
System.out.println("请输入数字!");
}
}
}
private static double getMoney() {
Scanner sc = new Scanner(System.in);
while (true) { //循环围住,直到输入合适的价格或者非法价格(往上层抛异常)
System.out.print("请输入合适的价格:");
double money = sc.nextDouble(); //假如输入非double型就会往上抛异常
if(money >= 0){
return money;
}else{
System.out.println("您输入的价格不合适吧");
}
}
}
}
运行结果:
可以大大增加程序的健壮性