0
点赞
收藏
分享

微信扫一扫

Java学习笔记一异常处理


如果执行try块里的业务逻辑代码时出现异常,系统自动生成一个异常对象,该异常对象被提交给Java运行时环境,这个过程被称为抛出异常。当Java运行时环境收到异常对象时,会寻找能处理该异常对象的catch块(依次判断该异常对象是否是catch块后异常类或其子类的实例),如果直到合适的catch块,则把该异常对象交给该catch块处理,这个过程被称为捕获异常;如果Java运行时环境找不到铺货异常的catch块,则运行时环境终止,Java程序也将退出。
不管程序代码块是否处于try块中,甚至包括catch块中的代码,只要执行该代码块时出现异常,系统总会自动生成一个异常对象。如果程序没有为这段代码定义任何的catch块,则Java运行时环境无法找到处理该异常的catch块,程序就在此退出。
Java把所有的非正常情况分为异常和错误,它们都继承Throwable父类。Error错误,一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错误,因此应用程序不应该试图使用catch块来捕获Error对象。在定义该方法时,也无须在其throws子句中声明方法可能抛出Error及任何子类。

Java 7新增的多异常捕获

在Java 7以前,每个catch块只能捕获一种类型的异常;但从Java 7开始,一个catch块可以捕获多种类型的异常。捕获多种类型异常时,多种异常类型用竖线隔开;异常变量有隐式的final修饰,程序不能对异常变量重新赋值,而使用捕获一种异常的写法,异常变量没有final修饰。

访问异常信息

如果程序需要在catch块中访问异常对象的相关信息,则可以通过访问catch块的后异常形参来获得。当Java运行时决定调用某个catch块来处理该异常对象时,会将异常对象赋给catch块后的异常参数,程序即可通过该参数来获得异常的相关信息

  • getMessage(): 返回该异常的详细描述字符串
  • printStackTrace(): 将该异常的跟踪栈信息输出到标准错误输出
  • printStackTrace(PrintStream s): 将该异常的跟踪栈信息输出到指定输出流
  • getStackTrace(): 返回该异常的跟踪栈信息

public class AccessExceptionMsg
{
public static void main(String[] args)
{
try{
FileInputStream fis = new FileInputStream("a.txt");
}catch(IOException ioe)
{
System.out.println(ioe.getMessage());
ioe.printStackTrace();
}
}
}

使用finally回收资源

不管try块中的代码是否出现异常,也不管哪一个catch块被执行,甚至在try块或catch块中执行了return语句,finally块总会被执行。如果在异常处理代码中使用System.exit(1)语句来退出虚拟机,则finally块将失去执行的机会。不要在finally块中使用如return或throw等导致方法终止的语句,一旦在finally块中使用return或throw语句,将会导致try块、catch块中的return、throw语句失效。当Java程序执行try、catch块时遇到了return或throw语句,这两个语句都会导致该方法立即结束,但是系统执行这两个语句并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,程序立即执行return或throw语句,方法终止;如果有finally块,系统立即开始执行finally块-只有当finally块执行完成后,系统才会再次跳回来执行try块、catch块里的return或throw语句;如果finally块里也使用了return或throw等导致方法终止的语句,finally块已经终止了方法,系统将不会跳回去执行try块、catch块里的任何代码。

Java 9增强的自动关闭资源的try语句

Java 7增强了try语句的功能-允许在try关键字后紧跟一对圆括号,圆括号可以 声明、初始化一个或多个资源,此处的资源指的是那些必须在程序结束时显式关闭的资源(如数据库连接、网络连接等),try语句在该语句结束时自动关闭这些资源。为了保证try语句正常关闭资源,这些资源实现类必须实现AutoCloseable或Closeable接口,实现这两个接口就必须实现close方法。Closeable是AutoCloseable的子接口,可以被自动关闭的资源类要么实现AutoCloseable接口,要么实现Closeable接口。Closeable接口里的close方法声明抛出了IOException,因此它的实现类在实现close方法时只能声明抛出IOException或其子类;AutoCloseable接口里的close方法声明了Exception,因此它的实现类在实现close方法时可以声明抛出任何异常。

public class AutoCloseTest
{
public static void main(String[] args) throws IOException{
try(
BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));
PrintStream ps = new PrintStream(new FileOutputStream("a.txt")))
{
System.out.println(br.readLine());
ps.println("hello world");
}
}
}

Java 9不要求在try后的圆括号内声明并创建资源,只需要自动关闭的资源有final修饰或者是有效的,Java 9 允许将资源变量放在try后的圆括号内。

public class AutoCloseTest
{
public static void main(String[] args) throws IOException{
// 有final修饰的资源
final BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));
//没有显式使用final修饰,但只要不对该变量重新赋值,该变量就是有效的final
PrintStream ps = new PrintStream(new FileOutputStream("a.txt"));
try(br;ps)
{
System.out.println(br.readLine());
ps.println("hello world");
}
}
}

方法重写时声明抛出异常的限制

使用throws声明抛出异常时有一个限制,就是方法重写时两小中的一条规则:子类方法声明抛出的异常类型应该是父类方法声明抛出的异常类型的子类或相同,子类方法声明抛出的异常不允许比父类方法声明抛出的异常多。

使用throw抛出异常

所有RuntimeException类及其子类的实例被称为Runtime异常;不是RuntimeException类及其子类的异常被称为Checked异常。
throw语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例。如果throw语句抛出的异常是Checked异常,则该throw语句要么处于try块里,显示捕获该异常,要么放在一个带throws声明抛出的方法中,即把该异常交给该方法的调用者处理;如果throw语句抛出的异常是Runtime异常,则该语句无须放在try块里,也无须放在带throws声明抛出的方法中;程序既可以显示使用try…catch来捕获并处理该异常,也可以完全不理会该异常,把异常交给调方法者处理。

自定义异常

用户自定义异常都应该继承Exception基类,如果希望自定义Runtime异常,则应该继承RuntimeException基类。定义异常类时通过需要提供两个构造器:一个是无参的构造器;另一个是带一个字符串参数的构造器,这个字符串将作为该异常对象的描述信息(也就是异常对象的getMessage()方法的返回值)。

public class AuctionException extends Exception
{
//无参的构造器
public AuctionException(){}
//带一个字符串参数的构造器
public AuctionException(String msg){ super(msg); }
}
public class AuctionTest
{
private double initPrice = 30.0;
public void bid(String bidPrice) throws AuctionException
{
double d = 0.0;
try{
d = Double.parseDouble(bidPrice);
}catch(Exception e){
e.printStackTrace();
//再次抛出自定义异常
throw new AuctionException("竞价必须是数值");
}
if(initPrice > d){ throw new AuctionException("竞价比起拍价低"); }
initPrice = d;
}
public static void main(String[] args){
AuctionTest at = new AuctionTest();
try{
at.bid("df");
}catch(AuctionException ae){
System.out.println(ae.getMessage());
}
}
}

异常链

从JDK 1.4以后,所有Throwable的子类在构造器中都可以接收一个cause对象作为参数,这个cause就用来表示原始异常,这样可以把原始异常传递给新的异常,使得即使在当前位置创建并抛出了新的异常,也可通过这个异常链追踪到异常最初发生的位置。

public class AuctionException extends Exception
{
//无参的构造器
public AuctionException(){}
//带一个字符串参数的构造器
public AuctionException(String msg){ super(msg); }
//创建一个可以接收Throwable参数的构造器
public AuctionException(Throwable t){ super(t); }
}


举报

相关推荐

0 条评论