一、概念
异常代表程序出现的问题(在Exception类中),例如读取的文件不存在了,读取网络数据时断网了...
Java的异常分为运行时异常和编译时异常。
二、运行时异常特点
编译时不报错,运行时出现异常。
三、运行时异常示例
public static void show(){
//特点:编译阶段不报错,运行时出现的异常,继承自 RuntimeException
int[] arr = new int[3];
//System.out.println(arr[3]);//运行时异常,程序在运行时,出现的异常,程序会中断,需要自己处理
//空指针异常
String str = null;
System.out.println(str);
System.out.println(str.length()); //NullPointerException
System.out.println("程序结束");
}
如上述代码,写了两种运行时异常,一种是数组访问越界,一种是查看空指针所代表的数组的长度的异常。
四、编译时异常特点
编译阶段必须处理,否则编译不通过。
五、编译时异常示例
public static void show2() { //将异常往调用它的地方抛
//编译时异常:编译阶段必须处理,否则编译不通过
//日期解析异常
String str = "2024-07-09 11:12:13";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = sdf.parse(str); //编译时异常,提醒我们处理
System.out.println(date);
InputStream is = new FileInputStream("d:/abc.txt");
}
上述代码有两个编译时异常,分别为日期解析异常(格式与上文不同)和IO异常。
编译时异常必须在编译时处理,否则编译不能通过,当然,当遇到编译时异常时还有一种处理方法,就是将此处的异常抛给上层处理,当调用这个方法时调用这个方法的方法进行处理这个异常。
用throws在方法名的形参列表的括号后抛出异常
语法
方法名() thorws 异常种类,异常种类........(可以连续抛多个异常)
public static void show2() throws ParseException, FileNotFoundException { //将异常往调用它的地方抛
//编译时异常:编译阶段必须处理,否则编译不通过
//日期解析异常
//ParseException指定抛出这个异常
String str = "2024-07-09 11:12:13";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = sdf.parse(str); //编译时异常,提醒我们处理
System.out.println(date);
//IO异常
InputStream is = new FileInputStream("d:/abc.txt");
}
存在多种异常时,可以用Exception抛出所有异常
public static void show2() throws Exception { //将异常往调用它的地方抛
//编译时异常:编译阶段必须处理,否则编译不通过
//日期解析异常
//ParseException指定抛出这个异常
String str = "2024-07-09 11:12:13";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = sdf.parse(str); //编译时异常,提醒我们处理
System.out.println(date);
//IO异常
InputStream is = new FileInputStream("d:/abc.txt");
//有多个异常时,可以连续抛出多个异常,也可以用Exception抛出所有异常
}
异常可以告知上层方法程序运行成功了还是失败了,运行时异常与编译时异常都可以上抛。
异常的简单处理方法:当下层的异常抛致最高层时,可以用try...catch方法来捕获异常
语法
try{
运行的方法
}catch(异常种类 变量名){
处理异常的方法
}
示例
package ExceptionDemo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo1 {
public static void main(String[] args) {
//目标:认识异常的体系,搞清楚异常的基本作用
//show();
try {
//监视代码,出现异常会被catch拦截住
show2();
} catch (Exception e) {
e.printStackTrace(); //打印这个异常信息
}
}
//运行时异常
public static void show(){
//特点:编译阶段不报错,运行时出现的异常,继承自 RuntimeException
int[] arr = new int[3];
//System.out.println(arr[3]);//运行时异常,程序在运行时,出现的异常,程序会中断,需要自己处理
//空指针异常
String str = null;
System.out.println(str);
System.out.println(str.length()); //NullPointerException
System.out.println("程序结束");
}
//编译时异常
public static void show2() throws Exception { //将异常往调用它的地方抛
//编译时异常:编译阶段必须处理,否则编译不通过
//日期解析异常
//ParseException指定抛出这个异常
String str = "2024-07-09 11:12:13";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = sdf.parse(str); //编译时异常,提醒我们处理
System.out.println(date);
//IO异常
InputStream is = new FileInputStream("d:/abc.txt");
//有多个异常时,可以连续抛出多个异常,也可以用Exception抛出所有异常
}
}
如上,上述代码中catch中使用的处理异常的方法是Exception类中的一个方法printStackTrace,可以用于打印出异常信息。
六、自定义异常
特点:编译时就报错,提示较为激进。
当我们需要在一个业务中对某些行为进行限制时,我们就可以使用自定义异常配合try catch方法来进行限制。
例如,当我们需要存储一个人的名字时,我们为了得到相对合理的信息,会做以下限制
1、年龄不能小于等于0岁
2、年龄不能大于等于200岁
此时,就可以定义一个类继承Exception类作为异常类,书写这个异常的限制,进行规范年龄输入。
示例()
package ExceptionDemo;
//自定义的编译式异常
//1、继承Exception
//2、重写构造方法
//3、哪里需要异常返回,在哪里抛出异常
public class IllegalAgeException extends Exception{
public IllegalAgeException() {
}
public IllegalAgeException(String message) { //message是异常的原因
super(message);
}
}
package ExceptionDemo;
public class ExceptionDemo3 {
public static void main(String[] args) {
//目标:认识自定义异常
//特点:编译就报错,提醒比较激进
System.out.println("开始");
//saveage(0); //编译时可以提醒别人修改
try {
saveage(0);
} catch (IllegalAgeException e) {
e.printStackTrace();
System.out.println("保存年龄失败");
}
System.out.println("结束");
}
//需求:公司收到了年龄小于1岁或大于200岁就是一个非法异常
public static void saveage(int age) throws IllegalAgeException
{
if (age<1 || age>200)
{
throw new IllegalAgeException("年龄非法");
}else {
System.out.println("年龄合法");
System.out.println("保存年龄"+age);
}
}
}
上述方法防止了年龄的错误输入,并重写了无参和有参构造器,可以通过有参构造器的super方法将错误信息传给父类进行打印。
自定义运行时异常继承的是RuntimeException,其他同理。
package ExceptionDemo;
public class IllegalAgeRutineException extends RuntimeException {
public IllegalAgeRutineException() {
super();// 调用父类的无参构造器,不写会默认添加
}
public IllegalAgeRutineException(String message) {
super(message);
}
}
package ExceptionDemo;
public class ExceptionDemo4 {
public static void main(String[] args) {
System.out.println("程序开始执行");
saveage(300);
System.out.println("程序结束");
}
//自定义运行时异常,也是储存年龄的方法
public static void saveage(int age) throws IllegalAgeRutineException
{
if (age<1 || age>200)
{
throw new IllegalAgeRutineException("年龄非法");
}else {
System.out.println("年龄合法");
System.out.println("保存年龄"+age);
}
}
}
七、异常的处理方案
示例:一个设置定价的业务,输入必须为double型(字符等类型就出现异常)
常见处理方法
1、底层异常都抛出给最外层调用者,最外层捕获异常,记录异常,响应合适信息给用户看。
package ExceptionDemo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo5 {
public static void main(String[] args) {
//目标:掌握异常的处理方案
//1、底层异常都抛出给最外层调用者,最外层捕获异常,记录异常,响应合适信息给用户看
System.out.println("程序开始");
try {
show2();
System.out.println("此处操作成功");
} catch (Exception e) {
e.printStackTrace();
System.out.println("此处操作失败");
}
System.out.println("程序结束");
}
public static void show2() throws Exception { //将异常往调用它的地方抛
//编译时异常:编译阶段必须处理,否则编译不通过
//日期解析异常
//ParseException指定抛出这个异常
String str = "2024-07-09 11:12:13";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = sdf.parse(str); //编译时异常,提醒我们处理
System.out.println(date);
InputStream is = new FileInputStream("d:/abc.txt");
//有多个异常时,可以连续抛出多个异常,也可以用Exception抛出所有异常
}
}
2、捕获异常,处理异常,继续执行
package ExceptionDemo;
import java.util.Scanner;
public class ExceptionDemo6 {
public static void main(String[] args) {
//目标:掌握异常的处理方案
//2、捕获异常,处理异常,继续执行
//接收用户的一个定价
System.out.println("程序开始");
while (true) {
try {
double price = userIputPrice();
System.out.println("用户成功设置了商品定价");
break;
} catch (Exception e) {
System.out.println("用户输入的定价有误,请重新输入");
}
}
System.out.println("程序结束");
}
public static double userIputPrice(){
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个价格:");
double price = sc.nextDouble();
return price;
}
}
当捕获到异常时输出设置的定价有误,并重新进入循环再次输入,知道正确设置定价后触发break方法退出循环。