目录
异常处理
1.1 概述
1.2 异常分类
1.3 异常处理
1.3.1 throws
1.3.2 try-catch
1.3.3 finally代码块
1.3.4 throw关键字
1.3.5 throw和throws的区别
1.4 自定义异常
1.4.1 概述
1.4.2 定义
1.4.3 自定义异常练习
在Java中,异常处理是一种机制,用于处理程序运行过程中可能发生的异常情况。异常是指在程序运行过程中发生的错误或意外情况,可能导致程序无法正常执行或出现不可预料的结果。
异常可以分为以下几类:
编译时异常:在代码编译过程中发生的异常,需要在编译时被捕获和处理,否则代码无法通过编译。比如语法错误、类型转换错误等。
运行时异常:在程序运行过程中发生的异常,通常是由于程序逻辑错误或意外情况导致的。运行时异常不需要强制要求在代码中显式捕获和处理,但如果不处理,会导致程序崩溃。比如除数为零错误、空指针异常等。
自定义异常:开发人员可以根据具体需求自定义异常类,用于处理特定的异常情况。自定义异常需要继承自标准异常类或其子类,并重写异常类的构造方法和其他方法。
错误:表示程序无法恢复的严重问题,通常是由于系统错误、资源不足等情况导致的。错误无法通过捕获和处理来解决,只能通过程序终止来处理。
Java中的异常处理两种方式,一是通过使用try-catch块来捕获和处理异常;try块用于封装可能会抛出异常的代码,而catch块用于捕获并处理try块中抛出的异常。二是通过throws声明在方法上,抛给外部调用的方法处理。
格式:
方法声明 throws 异常类名 {
}
说明:
使用throws处理异常,是用于方法声明上。不在方法内部处理,由外部调用的方法进行处理。处理方式仍然是try-catch或者throws。
下面是使用throws处理异常的方式,main方法后面加上throws ParseException。
package com.zhy.exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class TestException {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateS = "123";
//将字符串转换成日期时,如果dateS的格式和sdf定义的格式不一致,会抛出异常
sdf.parse(dateS);
}
}
格式:
try {
// 可能会抛出异常的代码,只有产生异常才会走到catch块内部
} catch (异常类名1 变量) {
// 处理异常的代码,在工作中,一般会把异常的信息记录到一个日志中
}
……
catch(异常类名n 变量名){
}
说明:
1.try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象。
2.如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try...catch之后的代码。
3.如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try...catch之后的代码。Throwable类中定义了三个异常处理的方法:
1.String getMessage():返回此Throwable的简短描述。
2.String toString():返回此Throwable的详细消息字符串。
3.void printStackTrace():JVM打印异常对象,默认此方法,打印的异常信息是最全面的。
下面是使用try-catch处理异常的方式,在main方法内部进行捕捉。
package com.zhy.exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class TestException {
public static void main(String[] args) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateS = "123";
sdf.parse(dateS);
}catch (ParseException e) {
e.printStackTrace();
}
}
}
当一段代码可能引发多种异常时,可以用多个catch捕捉详细的异常类,也可以用一个catch捕捉,将异常类型提升到Exception或者Throwable。
package com.zhy.exception;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/**
* 当代码块中可以产生多种异常,多种捕捉方式
*/
public class TestException {
/**
* 捕捉方式一:
* 使用throws声明在方法上,多个具体异常类型用逗号隔开。
*/
public void method1() throws ParseException, FileNotFoundException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateS = "123";
File f = new File("d:/note.txt");
//当字符串的格式不是日期时,会引发ParseException转换异常
sdf.parse(dateS);
//当文件不存在时,打开文件会引发FileNotFoundException文件找不到异常
new FileInputStream(f);
}
/**
* 捕捉方式二:
* 使用throws声明在方法上,用异常的基类Exception接收,或者更高级别Throwable。
*/
public void method2() throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateS = "123";
File f = new File("d:/note.txt");
//当字符串的格式不是日期时,会引发ParseException转换异常
sdf.parse(dateS);
//当文件不存在时,打开文件会引发FileNotFoundException文件找不到异常
new FileInputStream(f);
}
/**
* 捕捉方式三
* 使用try-catch在方法内部捕捉,多个异常用多个catch处理,对应具体的异常类型。
*/
public void method3() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateS = "123";
File f = new File("d:/note.txt");
try {
//当字符串的格式不是日期时,会引发ParseException转换异常
sdf.parse(dateS);
//当文件不存在时,打开文件会引发FileNotFoundException文件找不到异常
new FileInputStream(f);
}catch (ParseException e) {
e.printStackTrace();
}catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/**
* 捕捉方式四:
* 使用try-catch在方法内部捕捉,用一个catch处理,异常类型定义为异常基类Exception或者Throwable。
* @throws ParseException
* @throws FileNotFoundException
*/
public void method4(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateS = "123";
File f = new File("d:/note.txt");
try {
//当字符串的格式不是日期时,会引发ParseException转换异常
sdf.parse(dateS);
//当文件不存在时,打开文件会引发FileNotFoundException文件找不到异常
new FileInputStream(f);
}catch (Throwable e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
TestException e = new TestException();
//方式一和方式二是使用throws处理异常,所以调用者要接着处理,这里处理的方式仍然是往外抛
e.method1();
e.method2();
e.method3();
e.method4();
}
}
格式:
try {
// 可能会抛出异常的代码
} catch (异常类名 变量) {
// 处理异常的代码,在工作中,一般会把异常的信息记录到一个日志中
}finally{
// 无论是否出现异常都会执行,在工作中,一般用来关闭各种资源或者连接。
}
说明:
1.finally不能单独使用,必须和try一起使用。
2.finally一般用于资源释放(IO或者JDBC),无论程序是否出现异常,都会执行。
package com.zhy.exception;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestException {
public Date parseTest(String dateS) {
Date date = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
//将字符串转换成日期时,如果dateS的格式和sdf定义的格式不一致,会抛出异常
sdf.parse(dateS);
}catch (ParseException e) {
e.printStackTrace();
}finally {
date = new Date();
}
return date;
}
public static void main(String[] args) {
TestException exception = new TestException();
//返回:当前日期
//因为finally里面的代码无论如何都会执行,且会在try-catch后面执行;
//所以不管传递的是什么值,是否抛出异常,parseTest方法最后返回的都是当前日期;
//这个案例无实际意义,只是为了说明finally的执行逻辑,在工作中,一般都是用来释放IO流或者JDBC连接资源的。
Date date = exception.parseTest("9998-12-31");
System.out.println(date);
}
}
格式:
throw new 异常类名("异常产生的原因");
说明:
1.可以使用throw关键字在指定的方法中抛出指定的异常。
2.throw关键字必须写在方法的内部。
3.throw关键字后边new的对象必须是Exception类或者Exception的子类。
4.throw关键字抛出指定的异常对象,如果是运行时异常,可以不用处理;如果是编译时异常,必须采用throws或者try-catch处理异常。
throws与throw这两个关键字接近,不过意义不一样,有如下区别:
java提供的异常类,有时不满足我们使用的场景时,需要自己定义一些异常类。
格式:
public class XXException extends Exception | RuntimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
说明:
1.自定义异常类一般都是以Exception结尾,说明该类是一个异常类。
2.自定义异常类,必须是继承Exception或者RuntimeException。
继承Exception:那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try...catch
继承RuntimeException:那么自定义的异常类就是一个运行期异常,无需处理,交给虚拟机处理(中断处理)。
要求:
模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。
步骤一:定义异常类(RegisterException.java)
package com.zhy.exception;
public class RegisterException extends Exception{
//1.添加一个空参数的构造方法
public RegisterException() {
super();
}
//2.添加一个带异常信息的构造方法:所有异常类都会有一个带异常信息的构造方法,方法内部调用父类构造,由父类处理
public RegisterException(String message) {
super(message);
}
}
步骤二:测试异常类(TestException.java)
package com.zhy.exception;
import java.util.Scanner;
public class TestException {
public static void main(String[] args){
//1.使用数组保存已经注册过的用户名
String[] userNameArray = {"张三","李四","王武","赵立","张元"};
//2、使用Scanner获取用户输入的注册的用户名
System.out.println("请输入注册的用户名:");
Scanner sc = new Scanner(System.in);
String username = sc.nextLine();
//3.遍历存储已经注册过用户名的数组,判断用户名是否存在
boolean isExistUser = false;
for(int i = 0; i < userNameArray.length; i++) {
//如果用户名已经存在,抛出RegisterException异常,告知用户“亲,该用户名已经注册!”
if (userNameArray[i].equals(username)) {
isExistUser = true;
try {
throw new RegisterException("亲,该用户名已经注册!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
//4.如果循环结束了,还没有找到重复的用户名,提示用户“恭喜你,注册成功!”
if(!isExistUser) {
System.out.println("恭喜你,注册成功!");
}
}
}
输出结果:
1.注册失败场景,抛出自定义异常。
2.注册成功场景 。