JAVA异常

异常的概念

  • 常指在方法不能按照正常方式完成时,可以通过抛出异常的方式退出该方法,在异常中封装了方法执行过程中的错误信息及原因,调用方在获取该异常后可根据业务的情况选择处理该异常或者继续抛出该异常。
  • 在方法在执行过程中出现异常时,Java异常处理机制会将代码的执行权交给异常处理器,异常处理器根据在系统中定义的异常处理规则执行不同的异常处理逻辑(抛出异常或捕捉并处理异常)。

Java的异常体系

异常分类

在Java中,Throwable是所有错误或异常的父类,Throwable 又可分为Error和Exception

  • Error 指Java程序运行错误
    • 如果程序在启动时出现Error,则启动失败
    • 如果程序在运行过程中出现Error,则系统将退出进程
    • 出现Error通常是因为系统的内部错误或资源耗尽,Error不能被在运行过程中被动态处理。如果程序出现Error,则系统能做的工作也只能有记录错误的成因和安全终止。
    • 常见的Error有AWTError、ThreadDeath
  •  Exception 指Java程序运行异常
    • 运行中的程序发生了人们不期望发生的事件,可以被Java异常处理机制处理,可分为RuntimeException(运行时异常)和CheckedException(检查异常)
      • RuntimeException:指在Java虚拟机正常运行期间抛出该异常或者捕获并处理该异常。常见的RuntimeException有NullPointerException、ClassCastException、ArrayIndexOutOf BundsException等。
      • ​​​​​​​CheckedException:指在编译阶段Java 编译器会检查CheckedException异常并强制程序捕获和处理此类异常,即要求程序在可能出现异常的地方通过try catch语句块捕获并处理异常。常见的CheckedException有由于I/O 错误导致的IOException、SQLException、ClassNotFoundException等。该类异常一般由于打开错误的文件、SQL语法错误、类不存在等引起。

异常处理方式

异常处理方式有抛出异常使用try catch语句块捕获并处理异常这两种方式

(1)  抛出异常: 遇到异常时不进行具体处理,而是将异常抛给调用者,由调用者根据情况处理。有可能是直接捕获并处理,也有可能是继续向上层抛出异常。抛出异常有三种形式

  • throws: 作用在方法上,用于定义方法可能抛出的异常​​​​​​​
  • throw: 作用在方法内, 表示明确抛出一个异常
  • 系统自动抛出异

(2) 使用try catch捕获并处理异常

  • 用try catch 捕获异常能够有针对性地处理每种可能出现的异常,并在捕获到异常后根据不同的情况做不同的处理。 其使用过程比较简单:用try catch语句块将可能出现异常的代码包起来即可

throw和throws的区别

  • 位置不同:throws作用在方法上,后面跟着的是异常的类;而throw作用在方法内,后面跟着的是异常的对象
  • 功能不同:
    • throws用来声明方法在运行过程中可能出现的异常,以便调用者根据不同的异常类型预先定义不同的处理方式
    • throw用来抛出封装了异常信息的对象,程序在执行到throw时后续的代码将不再执行,而是跳转到调用者,并讲异常信息抛给调用者。也就是说,throw后面的语句块将无法被执行(finally语句块除外)

try catch语句

try{
    业务逻辑层
} catch(AException e){
    A异常的处理代码
} catch(BException e){
    B异常的处理代码
}...
  • 无论哪行代码发生异常,系统都会生成一个异常对象,这与try...catch...语句没有关系
  • 若程序没有对这个异常做任务处理,则程序在此退出,以前的程序中遇到的异常都是这种情况
  • 创建异常对象后,JVM会寻找可以处理它的catch块,并将异常对象交给这个catch去块处理
  • 左侧catch块的参数是Exception类型,是所有异常的父类,所以它能处理所有的异常信息
  • 程序应该先处理小异常,再处理大异常,即将处理父类异常的catch块放在处理子类异常的catch块之后

访问异常信息

方法

描述

String getMessage()

返回该异常的详细消息字符串

StackTraceElement[] getStackTrace()

返回该异常的跟踪栈信息

void printStackTrace()

将该异常的跟踪栈信息打印到标准输出设备

 自动关闭资源的try语句

Java 7中增强了try语句的功能,允许自动关闭资源!

try(
    声明、初始化N个资源;
){
    ...
}catch(Exception e){
    ...
}
  • try语句会在结束时自动关闭这些资源
  • 该资源的实现类必须实现如下接口之一:AutoCloseable、Closeable
  • 自动关闭资源的语句可以不用catch和finally

声明抛出异常

throws ExceptionClass1, ExceptionClass2,...
  • throws语句用于标志某方法可能抛出的异常,它必须位于方法签名之后
  • throws语句声明抛出异常后,程序中无需使用try语句捕获该异常了
  • 在重写时,子类方法声明抛出的异常类型不能比父类方法声明抛出的异常类型大。

自定义异常

  • 若定义Checked异常,则继承于Exception
  • 若定义Runtime异常,则继承于RuntimeException
  • 自定义的异常类,通常需要提供如下构造函数
public SomeException(){}
public SomeException(String message){}
public SomeException(String meassge, Throwable cause){}

示例

//最终打印的结果为-1
System.out.println(process3("abc"));  

public static String inputUsername() throws UsernameException{
	System.out.println("请输入账号:");
	try(
		Scanner scanner = new Scanner(System.in);

	){
		String username = scanner.nextLine();
		if(!username.matches("^\\w{6,20}$)"){
			throw new UsernameException("账号格式错误!");
		}
		return username;
	}
	//除主动抛出的异常外,在程序的运行过程中也可能会抛出其他异常,因此最好写上一个catch,保证更加的严谨
	catch(RuntimeException e){
		throw new UsernameException("输入账号失败!", e);
	}
}

除主动抛出的异常外,在程序的运行过程中也可能会抛出其他异常,因此最好写上一个catch,保证更加的严谨

异常跟踪栈

  • 程序运行时,经常会发生一系列方法调用,从而形成方法调用栈
  • 异常机制会导致异常在这些方法之间传播,而异常的传播顺序与方法的调用相反
  • 异常从发生异常的方法向外传播,首先传给该方法的调用者,再传给上层调用者
  • 最终传到main方法,若依然没有得到处理,则JVM会终止程序,并打印异常跟踪栈信息。

先调用的方法在栈底,后调用的方法在栈顶。想象一下调用的入栈方式,main方法调用method1,method1调用method2,method2调用method3(异常发生在method3方法之内)。

通常情况下,我们只需关注异常的抛出位置,关注抛出异常的我们自己写的方法。而且最好e.printStackTrace(),而不是直接输出,因为打印栈信息可以帮助我们更好的定位出错位置。如果在catch中不处理的话,应该继续往下抛,throw。

异常处理的原则

  • 不要过度的使用异常,不要用异常处理代替错误代码处理,不要用异常处理代替流程控制语句;
  • 不要忽略捕获的异常:对于捕获到的异常,要进行合适的修复,对于不能处理的部分,应该抛出异常;
  • 不要直接捕获所有的异常:应针对不同的异常做出有针对性的处理,而捕获所有的异常,容易压制(丢失)异常;
  • 不要使用过于庞大的try代码块:庞大的try块会导致业务过于复杂,不利于分析异常的原因,也不利于程序的阅读及维护

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值