什么是异常
java中的异常是指java程序在运行时可能出现的错误或非正常情况。例如在程序中试图打开一个根本不存在的文件,在程序中除0。
异常是否出现,通常取决于程序的输入、程序中对象的当前状态以及程序所处的运行环境。
程序抛出异常后,会对异常进行处理。异常处理将会改变程序的控制流程,出于安全性考虑,同时避免异常程序影响其他正常程序的运行,操作系统通常将出现异常的程序强行终止,并弹出系统错误提示。
> public class test1 {
public static void main(String[] args) {
int result = divide(4, 0);
System.out.println(result);
}
public static int divide(int x,int y){
int result=x/y;
return result;
}
}
由上可知,程序抛出了算术异常(ArithmeticException),提示运算时出现了被0除的情况。异常发生后,程序会立即结束,无法继续向下执行。
ArithmeticException是一个异常类,java提供了大量的异常类,每一个异常类都表示一种预定义的异常,这些异常类都继承自java.lang包下的Throwable类,
Throwable类是所有异常类的父类,它有两个直接子类:Error类和Exception类,其中,Error类代表程序中产生的错误,Exception类代表程序中产生的异常。
● Error类称为错误类,它表示java程序运行时产生的系统内部错误或资源耗尽的错误,这类错误比较严重,仅靠修改程序本身是不能恢复执行的。例如,使用java命令运行一个不存在的类就会出现Error错误。
● Exception类称为异常类,它表示程序本身可以处理的错误,在java程序中进行的异常处理,都是针对Exception类及其子类的。在Exception类的众多子类中有一个特殊的子类——RuntimeException类,该类及其子类用于表示运行时异常。Exception类的其他子类都用于表示编译时异常。
从JavaAPI中查阅可知,Error错误类的子类:
Examption错误类的子类:
Throwable常用方法
方法声明 | 功能描述 |
---|---|
String getMessage() | 返回异常的消息字符串 |
String toString() | 返回异常的简单信息描述 |
void printStack Trace() | 获取异常类名和异常信息以及异常出现在程序中的位置,把信息输出到控制台 |
运行时异常和编译时异常
在实际开发中,经常会在程序编译时产生异常,这些异常必须处理,否则程序无法正常运行,这种异常被称为编译时异常,也称为check异常。
还有一种异常是在程序运行时产生的,这种异常即使不编写异常处理代码,依然可以通过编译,因为被称为运行时异常,也称为unchecked异常。
编译时异常
在Exception类中,除了RuntimeException类以外,其他子类都是编译时异常。java编译器会对编译时异常进行检查。出现异常必须对其进行处理。
处理编译时异常的两种方式:
● 使用try…catch语句对异常进行捕获处理。
● 使用throws关键字声明抛出异常,由调用者对异常进行处理。
运行时异常
RuntimeException类及其子类都是运行时异常。运行时异常是在程序进行时由java虚拟机自动进行捕获的,java编译器不会对异常进行检查。不需要上述语句或关键字声明,程序也能编译通过,只是在运行过程可能报错。
常见的运行时异常:
运行时异常 | 描述 |
---|---|
ArithmeticException | 算术异常 |
IndexOutOfBoundException | 索引越界异常 |
ClassCastException | 类型转换异常 |
NullPointerException | 空指针异常 |
NumberFormatException | 数字格式化异常 |
运行时异常一般是由程序中的逻辑错误引起的,在程序运行时无法恢复,例如,通过数组的索引访问数组的元素时,如果索引超过了数组范围,就会发生索引越界异常,代码如下:
int[]arr=new int[5];
System.out.println(arr[6])
运行时产生数组越界异常
异常处理及其语法
异常的产生及处理
一般情况下,当程序在运行过程中发生了异常时,系统会捕获抛出的异常对象并输出相应的信息,同时终止程序的运行。这种情况并不是用户所期望的,因为需要让程序接收和处理异常对象,从而避免影响其他代码的执行。
当一个异常类的对象被捕获或接收后,程序就会发生流程跳转,系统中止当前的流程而跳转到专门的异常处理语句块,或直接跳出当前程序和java虚拟机回到操作系统。
处理异常的5个关键字
关键字 | 功能描述 |
---|---|
try | 放置可能引发异常的代码块 |
catch | 后面对应异常类型和代码块,该代码用于处理这种类型的异常 |
finally | 主要用于回收在try代码块里打开的物理资源 ,如,数据库连接,网络连接和磁盘文。异常机制保证finally代码块总是被执行 |
threw | 用于抛出一个实际的异常,它可以单独作为语句来抛出一个具体的异常对象 |
throws | 用在方法签名中,用于声明该方法可能抛出的异常 |
try…catch语句
在进行除0运算时发生了异常导致程序立即终止,所以程序无法继续执行发生异常后的代码。为了使异常发生后的程序代码正常运行,程序需要捕获异常并进行处理。
java提供了try…catch语句用于捕获并处理异常,其语法格式如下:
try{
代码块
}catch(ExceptionType e){
代码块
}
try代码中编写可能发生异常的java语句,在catch代码种编写针对异常进行处理的代码。
当try代码块中的程序发生了异常时,系统会将异常的信息封装成一个异常对象,并将这个对象传递给catch代码进行处理。
catch代码块需要一个参数指明它能够接收的异常类型,这个参数必须是Exception类或其子类。
编写try…catch语句时,需要注意以下几点:
● try代码块是必须的
● catch代码块可以有多个,但捕获父类异常的catch代码块必须位于捕获子类异常的catch代码块后面
●catch代码块必须位于try代码块后面
try…catch语句的异常处理流程图如下:
对除0运算中的异常信息进行捕获:
public class test1 {
public static void main(String[] args) {
try {
int result = divide(4, 0);
System.out.println(result);
}catch (Exception e)
{
System.out.println("捕获的异常信息为:"+e.getMessage());
}
System.out.println("程序继续向下执行");
}
public static int divide(int x,int y){
int result=x/y;
return result;
}
}
在try代码块中,发生异常的语句后面的代码是不会被执行的。
finally语句
有时候希望一些语句无论程序是否发生异常都需要执行,这时就可以在try…catch语句后加一个finally代码块。
finally代码块是try…catch…finally或try…finally结构的一部分,finally代码块只能出现在try…catch或try代码块之后,不能单独出现。
语法结构如下:
try{
代码块
}catch(Exceptiontype e){
代码块
}finally{
代码块
}
try…catch…finally语句的异常处理流程图如下:
public class test1 {
public static void main(String[] args) {
try {
int result = divide(4, 0);
System.out.println(result);
}catch (Exception e)
{
System.out.println("捕获的异常信息为:"+e.getMessage());
return;//用于结束当前的方法
}finally{
System.out.println("进入finnally代码块");
}
System.out.println("程序继续向下执行");
}
public static int divide(int x,int y){
int result=x/y;
return result;
}
}
在catch语句中添加了return语句作为方法的结束,第13行代码就不会执行了。但是finall代码块中的代码会执行,不受return语句影响。无论程序发生异常还是使用return语句结束,final代码块中的语句都会执行。
在程序设计时,通常会使用finally代码块处理必须做的事情,如释放系统资源。System(0)表示退出当前的java虚拟机,任何代码都不能再执行。
抛出异常
有些异常不需要处理,此时可以将异常抛出,让该类的调用者处理,java提供了throws关键字和throw关键字用于抛出异常。
throws关键字
实际开发中,大部分情况下程序开发者会调用别人的方法,并不知道别人编写的方法是否会发生异常。
java允许在方法的后面使用throws关键字声明该方法有可能发生的异常,这样调用者在调用该方法时,就明确地知道该方法有异常,必须对异常进行处理。
语法格式:
修饰符 返回值类型 方法名(参数1,参数2,…)throws 异常类1,异常类2,…{
方法体
}
public class test1 {
public static void main(String[] args) {
int result=divide(4,2);
System.out.println(result);
}
public static int divide(int x,int y) throws Exception{
int result=x/y;
return result;
}
}
传入第二个参数为2,运行程序依然会提示错误,这是因为定义divide()方法时使用throws关键字声明了该方法可能抛出的异常,调用者必须在调用divide()方法时对抛出的异常进行处理。
public class test1 {
public static void main(String[] args) {
try {
int result=divide(4,2);
System.out.println(result);
}catch(Exception e)
{
e.printStackTrace();//打印捕获的异常信息
}
}
public static int divide(int x,int y) throws Exception{
int result=x/y;
return result;
}
}
在调用方法时,如果不知道如何处理声明抛出的异常,也可以使用throws关键字继续将异常抛出,这样程序也能编译通过。使用throws关键字重抛异常时,程序发生了异常,并且上一层调用者也无法处理异常时,那么异常会继续被向上抛出,最终直到系统接收到异常,中止程序执行。
public class test1 {
public static void main(String[] args)throws Exception{//将divide方法声明的异常继续抛出
try {
int result=divide(4,0);
System.out.println(result);
}catch(Exception e)
{
e.printStackTrace();
}
}
public static int divide(int x,int y) throws Exception{
int result=x/y;
return result;
}
}
main方法继续使用throws关键字将Exception抛出,程序虽然可以通过编译,但并没有对异常进行处理,程序中止运行。
throw关键字
与throws关键字不同,throw关键字用于方法体内,抛出的是一个异常实例,每次只能抛出一个异常实例。
语法格式
throw ExceptionInstance
在方法中,通过throw关键字抛出异常后,还需要使用throws关键字或try…catch语句对异常进行处理。
如果throw抛出的是Error、RuntimeException或它们的子类异常对象,则无需使用上述对异常进行处理。
使用throw关键字抛出异常,通常有以下两种情况
●当throw关键字抛出的异常时编译时异常时,有两种处理方式:
Ⅰ在try代码块里使用throw关键字抛出异常,通过try代码块捕获该异常;
Ⅱ在一个有throws声明的方法中使用throw关键字抛出异常,把异常交给该方法的调用者处理。
●抛出的异常时运行时异常时,程序既可以显示使用try…catch语句捕获并处理该异常,也可以完全不理会该异常,而把该异常交给方法的调用者处理。
public class test1 {
public static void printAge(int age) throws Exception{
if(age<0){
throw new Exception("输入的年龄有误,必须是正整数");
}
else {
System.out.println("此人年龄为:"+age);
}
}
public static void main(String[] args) {
int age=-1;
try {
printAge(age);
}catch (Exception e){
System.out.println("捕获的异常信息为:"+e.getMessage());
}
}
}
上述代码中,throws声明的printAge方法中使用throw抛出异常实例,将异常交给main方中的调用者处理,交给catch方法处理该异常。
自定义异常类
自定义异常类解决程序开发中程序中特有的异常情况。
自定义异常类必须继承Exception类或其子类。
使用自定义异常类,需要用到throw关键字。使用throw关键字在方法中声明异常的实例对象。声明格式如下
throw Exception 异常对象
class DivideByMinusException extends Exception{
public DivideByMinusException(){//调用Exception无参构造方法
super();
}
public DivideByMinusException(String message)//调用Exception有参构造方法
{
super(message);
}
}
public class test1 {
public static void main(String[] args) {
int result=divide(4,-2);
System.out.println(result);
}
public static int divide(int x,int y){
if(y<0){
throw new DivideByMinusException("除数是负数");
}
int result=x/y;
return result;
}
}
程序编译时出现了异常,在一个方法内使用throw关键字抛出异常对象时,需要使用try…catch语句对抛出的异常进行处理,或在divide方法后面使用throws关键字声明抛出对象,由该方法的调用者处理。
class DivideByMinusException extends Exception{
public DivideByMinusException(){//调用Exception无参构造方法
super();
}
public DivideByMinusException(String message)//调用Exception有参构造方法
{
super(message);
}
}
public class test1 {
public static void main(String[] args) {
try {
int result=divide(4,-2);
System.out.println(result);
}catch (DivideByMinusException e){
System.out.println(e.getMessage());
}
}
public static int divide(int x,int y) throws DivideByMinusException{
if(y<0){
throw new DivideByMinusException("除数是负数");
}
int result=x/y;
return result;
}
}