Exception异常
Java具有健壮性:
- GC垃圾回收
- 异常处理机制
throwable是所有异常和错误的父类
错误error:
是一个类
public class Error extends Throwable
错误是无法处理的,只能终止,一般这些错误是与虚拟机内存/内核有关。
异常Exception:
所有异常的父类,所有的异常是可以处理的。
常见异常:
ArithmeticException
NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
- 运行时的异常:(Runtime Exception)
编译的时候没有出现问题,用户提交数据运行时会引发的异常。
- 编译时的异常(checked exception) 大类Exception也是编译时异常
在编译的时候就出现问题的异常。
除了runtime exception其他都是checked exception
代码里面出现异常如果不处理,当前main线程终止
异常处理:
tips:不允许在代码里面对任意一个运行时异常处理,提前预判
1.捕获
try catch finally【快捷键Ctrl+Alt+T】,真正处理异常的方法
语法:
try{
//可能出现异常的代码块
}catch(异常类型 对象名称){
//处理异常对象方法
}finally{
//不管程序里面是否出现异常,finally代码块的功能肯定会被执行
//资源释放
}
ctrl+alt+t快捷键
try{
//可能会出现的异常代码块
}catch(异常种类 异常对象){
//异常处理方法
}finally{
//资源回收,一定会被执行
}
jdk1.8之后推出自动回收:
try(需要回收的资源){
}catch(异常种类 异常对象){
//异常处理方法
}
catch里面常用的异常处理方法:
catch(异常类 异常对象){
/*
1.system.out.println;
2.异常对象.printStackTrace();这里面打印的顺序是随机的,底层是system.err,不是system.out
3.system.out.print(异常对象.getMessage());
4.return 数据;
5.异常+日志:将异常信息存储到不同级别的日志文件中 info warn error debug
6. 异常信息的传递throw(将低级别的异常对象传递到高级别的异常对象中 casued by:)
*/
}
int[] array=new int[3];
System.out.println(array[2]);
try{
System.out.println(array[3]);}
catch (ArrayIndexOutOfBoundsException a){
System.out.println("数组越界");
}
finally{
}
try里面异常之后的代码不会被执行,里面有多个异常时候我们选用多个catch,可以用||简化很多的异常,但是要注意异常的等级关系,如果写了子类异常,在||后面不可以加父类,可以写多个catch,虽然有多个catch,但只执行一个catch,要注意前后catch的异常范围,如果前面异常范围过大,后面的异常不会处理,因此放在前面的catch异常范围会小于后面的范围,要将异常的代码try住,正常代码不用try
try {
if(str.equals(s)) System.out.println("true");
else System.out.println("false");
System.out.println(3/0);
} catch (NullPointerException e) {
e.printStackTrace();
}
catch (ArithmeticException a){
a.printStackTrace();
}
finally {input.close();
}
一个异常可能会导致多个异常,此时需要看casued by。
对于编译时异常:也是一样的try...catch
public static final String PATTAN="yyyy-mm-dd";
//这里格式需要跟下面字符串里面time格式一致或者少于string的
public static void main(String[] args) {
//将string转date,格式化字符串的时间
String renttime="2022-10-24";
String backtime="2023-10-18";
System.out.println(gettime(renttime, backtime)/1000/3600/24);
//转化成天数输出
}
private static long gettime(String renttime,String backtime){
SimpleDateFormat simpleDateFormat=new SimpleDateFormat(PATTAN);
Date backdate=null;
Date rentdate=null;//先赋值,扩大变量作用域
try{
rentdate= simpleDateFormat.parse(renttime);
backdate= simpleDateFormat.parse(backtime);
//出现编译时异常parseException,,需要try...catch,
}catch(ParseException e){
e.printStackTrace();
}
//将date转换成数值类型
long rent=rentdate.getTime();//gettime只能得到当前日期毫秒数
long back=backdate.getTime();
return Math.abs((rent-back));
}
2.抛出
throws
把异常抛出给调用者,表示没有能力处理(消极处理),不处理运行时异常
语法:
在方法的签名后面,使用throws抛出具体异常类
public static void fun() throws ClassNotFoundException {
Class.forName("abd");
}
但是没有做处理,而且该方法在main中调用的话仍然需要try...catch,做出异常提示
tips:throw和throws不一样的
throws是处理异常的一种方式,在方法后面抛出多个异常类,自己没有能力处理异常。
throw:
控制代码执行流程,catch里面经常用,遇见throw关键字,程序结束,语法:抛出一个异常对象
private static double divide(int num1,int num2){
//提前预判数据,除数不能为零
if(num2==0){
//System.exit(-1);这个不会展示异常日志,throw可以展示异常日志
// 只在Java程序中意义无法停止其他web或者其他项目
// 因此此时可以用throw控制流程
throw new ArithmeticException();
//或者返回具体信息throw new ArithmeticException("除数不能为零");
}
return num1/num2;
}
由此可以改进用户登录的方法:
private boolean login(String name,String pass){
if(name==null||pass==null){
throw new NullPointerException("用户名或密码不能为空");
}
//与下面方法是一样的,只是下面是分开确认
Objects.requireNonNull(name,"用户名不能为空");
Objects.requireNonNull(pass,"密码不能为空");
return true;
}
前面我们说过了可以在catch里面加上throw来实现异常信息的传递,此时throw是由低级异常传到高级异常,所以在catch里面的throw需要抛出catch异常类型的父类异常,
try{
}catch(ParseException e){
throw new Exception("错误信息", e);
}
但是此时子类异常创建父类异常对象,会发生错误,也就是处理类型转换异常一样的,再次try...catch
try{
}catch(ParseException e){
try {
throw new Exception("错误信息", e);
} catch (Exception e1) {
e1.printStackTrace();
}
}
自定义异常类
自己定义的异常原因和反馈,一般都是与throw结合使用,为了满足需求而自定义的一个异常,一般类里面只有重载方法:
//编写一个银行取钱的项目:
//存款为1000,取钱的时候想取2000
public static void main(String[] args) {
double money=1000;
double getmoney=2000;
get$(money,getmoney);
}
private static void get$(double money,double getmoney){
if(money<getmoney){
// 取不出来,抛出异常,该方法结束
}
money-=getmoney;
}
/*很显然取不出来,这时候可以抛出自定义的异常来展示错误信息“账户余额不足”,并且继承我们的异常父类(记得重写方法),继承编译时异常父类exception,或者继承运行时异常父类runtime exception*/
private static void get$(double money,double getmoney){
if(money<getmoney){
throw new BalanceException("账户余额不足");
}
}
上面是自定义一个继承RuntimeException的异常类,但是如果我换成继承Exception父类的话呢?由于Exception类是一个编译时异常类,对于编译时异常,我们一般在方法签名后面加上throws某某类异常,并且在调用该方法时仍需要try...catch:
public static void main(String[] args) {
double money=1000;
double getmoney=2000;
try {
get$(money,getmoney);
} catch (BalanceException e) {
e.printStackTrace();
}
}
private static void get$(double money,double getmoney)throws BalanceException{
if(money<getmoney){
throw new BalanceException("账户余额不足");
}
money-=getmoney;
}
tips:某些异常对应某些code,例如:账户余额不足对应-->1001,所以在自定义异常类中会有属性code,用于给程序员反馈异常信息。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?