数据结构,对循环队列,双端队列的总结:
刷题:
异常处理
对于构造大型、健壮、可维护的应用,错误处理是整个应用要考虑的重要方面。
在Java中,Exception类是所有异常的基类,它有很多子类,主要包括以下几种:
- Checked Exception:编译时异常,也称为受检异常。这种异常在代码编译期间就必须被处理或声明抛出,否则无法通过编译。常见的 Checked Exception 有 IOException、ClassNotFoundException 等。
- Unchecked Exception:运行时异常,也称为非受检异常。这种异常是在代码运行期间才会被检测到,并且不需要明确地声明抛出。常见的 Unchecked Exception 有 NullPointerException、ArraylndexOutOfBoundsException 等。
- Error:表示严重的、不可恢复的错误,通常是JVM内部问题导致的异常,例如OutOfMemoryError、StackOverflowError 等。与 Exception 不同,Error不应该被程序员捕获和处理,而是应该尽量避免出现这些错误。
- RuntimeException:运行时异常,是 Unchecked Exception 的子类,这种异常通常是由程序逻辑错误引起的,例如除数为0、数组下标越界等。
- 自定义异常:根据需要,还可以自定义异常类,继承于Exception 或 RuntimeException,并针对具体的业务场景来进行异常类型的定义和扩展,以便更好地进行异常处理和调试。
处理机制
Java 的异常处理机制可以让程序具有极好的容错性,当程序运行出现意外情形时,系统会自动生成一个 Exception 对象来通知程序,从而实现将“业务功能实现代码”和“错误处理代码分离”。
使用 try...catch 捕获异常
一个 catch 可以捕获多种类型的异常,需要注意下面两个地方:
- 捕获多种类型的异常时,多种异常类型之间用竖线(|)隔开
- 捕获多种类型的异常时,异常变量有隐式的 final 修饰,因此程序不能对异常变量重新赋值
package com.ittht.day10;
public class MultiException {
public static void main(String[] args) {
try{
int a=Integer.parseInt(args[0]);
int b=Integer.parseInt(args[1]);
int c=a/b;
System.out.println("相除的结果是:"+c);
}
catch(IndexOutOfBoundsException|NumberFormatException|ArithmeticException ie){
System.out.println("程序发生了数组越界、数学格式异常、算术异常之一");
}
catch (Exception e){
System.out.println("未知异常");
//捕获一种类型的异常时,异常变量没有final修饰,所以可以赋值
e=new RuntimeException("test");
}
}
}
其中的 args[0] 代表的是传入的第一个参数,args[1] 是传入的第二个参数。
访问异常信息
常用方法:
- getMessage():返回该异常的详细字符串
- printStackTrace():将该异常的跟踪栈信息输出到指定输出流
- printStackTrace(PrintStream s):将该异常的跟踪栈信息输出到指定输出流
- getStackTrace():返回该异常的跟踪栈
package com.ittht.day10;
import java.io.FileInputStream;
import java.io.IOException;
public class AccessExceptionMsg {
public static void main(String[] args) {
try{
FileInputStream fit=new FileInputStream("a.txt");
}
catch (IOException ioe){
//调用了Exception对象的getMessage()方法来得到异常对象的详细信息
System.out.println(ioe.getMessage());
//使用printStackTrace()方法来打印该异常的跟踪信息
ioe.printStackTrace();
}
}
}
FileInputStream 是 Java IO 体系中的一个文件输入列,用于读取磁盘中的内容。
使用 finally 回收资源
有时程序在 try 中打开了一些物理资源(数据库连接,网络连接和磁盘文件),这些物理资源都必须显示回收。Java中的垃圾回收机制不会回收物理资源,只能回收堆内存中对象占用的内存。
如果 try 块中的某条语句发生了异常,该语句后面的其他语句通常不会获得执行的机会,位于该语句之后的资源回收局域不能执行;
如果在 catch 块中进行资源回收,但 catch 语句完全有可能不能执行,这也会导致不能回收这些物理资源。
所以异常处理机制提供了 finally 块,finally 块总会被执行。
try{ //业务实现代码 } catch(SubException e){ //异常处理1 } catch(SubException2 2){ //异常处理2 } finally{ //资源回收块 }
异常处理语句中 try 语句是必须的,但 catch 和 finally 块至少出现一个。
多个 catch 块必须位于 try 块之后。
finally 块必须位于所有的 catch 块之后。
package com.ittht.day10;
import java.io.FileInputStream;
import java.io.IOException;
public class FinallyTest {
public static void main(String[] args) {
FileInputStream fis=null;
try{
fis=new FileInputStream("a.txt");
}
catch(IOException ioe){
System.out.println(ioe.getMessage());
//return语句强制方法返回
return;
//使用exit退出虚拟机/*注释掉return后,使用该条语句的时候不会执行finally块*/
//System.exit(1);
}
finally {
if(fis!=null){
try{
fis.close();
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
System.out.println("执行finally块里面的资源回收");
}
}
}
除非在 catch 语句中调用了退出虚拟机的方法,否则不管在 try 块、catch 块中执行了什么样的代码,异常处理的 finally 块总会被执行。
不要在 finally 块中使用 return 或 throw 语句,将会导致 try 块、catch 块中的 return 、throw 语句失效。
package com.ittht.day10;
public class FinallyFlow {
public static void main(String[] args)
throws Exception
{
boolean a = test();
System.out.println(a);
}
public static boolean test(){
try{
//finally块中包含了return语句
//所以下面的return语句失去作用
return true;
}
finally{
return false;
}
}
}
异常处理的嵌套
Closeable 是 AutoCloseable 的子接口,可以被自动关闭的资源类要么实现 Closeable接口,要么实现 AutoCloseable 接口。
Closeable 接口里的 close() 方法声明抛出来 IOException,所以它的实现类在实现 close 方法是只能声明抛出 IOException 或其子类。
AutoCloseable 接口的 close() 方法声明抛出来了 Exception ,所以它的实现类在实现 close()方法是可以声明抛出任何异常。
下面的代码是使用自用关闭资源的 try 语句:
package com.ittht.day10;
import java.io.*;
public class AutoCloseTest {
public static void main(String[] args)
throws IOException
{
try(
//声明、初始化两个可关闭的资源
//try语句会自动关闭这两个资源
BufferedReader br=new BufferedReader(
new FileReader("AutoCloseTest.java"));
PrintStream ps=new PrintStream(new FileOutputStream("a.txt")))
{
//使用两个资源
System.out.println(br.readLine());
ps.println("java");
}
}
}
BufferedReader 和 PrintStream 都实现类 Closeable 接口,而且放在 try 语句中声明和初始化,所以 try 语句会自动关闭它们。
自动关闭资源的 try 语句后也可以带多个 catch 块和一个 finally 块。
Checked 异常和 Runtime 异常体系(运行时异常)
所有的 RuntimeException 类及其子类的实力被称为 Runtime 异常;其他的被称为 Checked 异常。
Checked 异常的处理方式——没有完善错误的代码不会被执行。
- 知道异常时,用 try...catch 块来捕获异常并在 catch 块中修复。
- 不知道如何处理该异常时,定义方法时声明抛出异常
Runtime 异常可以不用显式声明抛出,如果要捕获的话,也可以用 try...catch 块实现。
用 throw 声明抛出异常
throw 声明抛出的语法格式跟在方法签名之后(只能在方法签名中使用):
throws ExceptionClass1,ExceptionClass2...
如果某段代码调用量一个带 throws 声明的方法,该方法声明抛出了 Checked 异常,说明该方法希望它的调用者来处理。调用该方法要么放在 try 块中显式捕获该异常,要么放在另一个带 throws 声明抛出的方法中。
package com.ittht.day10;
import java.io.FileInputStream;
import java.io.IOException;
public class ThrowTest2 {
public static void main(String[] args)
throws Exception {
test();
}
public static void test()
throws IOException{
FileInputStream fis=new FileInputStream("a.txt");
}
}
方法重写时声明抛出异常的限制
使用 throws 声明抛出异常时有一个限制:
子类方法声明抛出的异常类型,不应该比父类方法声明抛出的异常类型多。
使用 Throw 抛出异常
语法格式为:
trows ExceptionInstance;
package com.ittht.day10;
public class ThrowTest {
public static void main(String[] args) {
try{
//调用声明抛出Checked异常的方法,
//要么显式捕获,要么在main方法中再次声明抛出
throwChecked(-3);
}
catch (Exception e){
System.out.println(e.getMessage());
}
throwRuntime(3);
}
public static void throwChecked(int a)
throws Exception{
if(a>0){
//自行抛出Exception异常
//该代码不许处于try块里或者处于带throws声明的方法里
throw new Exception("a的值大于0,不符合要求");
}
}
public static void throwRuntime(int a){
if(a>0){
//自行抛出Exception异常
//也可不理会该异常,把异常交给该方法调用者处理
throw new RuntimeException("a的值大于0,不符合要求");
}
}
}
自定义异常类
自定义异常类都应该继承 Exception 基类。
如果希望定义一个 Runtime 异常,贼一个继承 RuntimeException 基类。
第一异常类时要提供两个构造器:一个无参数的构造器,另一个是带字符串参数的构造器。
package com.ittht.day10;
public class AuctionException extends Exception{
public AuctionException(){}
public AuctionException(String msg){
//通过super来调用父类的构造器,这行代码可以将此字符串参数传给异常对象的message属性
//该message属性就是异常对象的详细描述
super(msg);
}
}
catch 和 throw 同时使用
异常的处理方法有两种:
- 在出现异常的方法内捕获并处理异常,方法的调用者不能再次捕获该异常
- 在方法签名中什么抛出该异常,将该异常完全交给方法调用者处理
所以有异常时,单靠某个方法不能完全处理该异常:比如在异常出现时,程序值对该异常进行部分处理,还有些处理需要再该方法的调用者中才能完成,大于一个再次抛出异常,让该方法的调用者也可以捕获到该异常。
package com.ittht.day10;
public class AuctionTest {
private double initPrice=30.0;
//因为该方法中显式抛出了AuctionException异常
//所以此处需要声明抛出AuctionException异常
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){
//再次捕获到bid()方法中的异常,并对异常进行处理
System.err.println(ae.getMessage());
}
}
}
throw 抛出异常时是应用后台(控制台)记录了异常发生的详细情况
catch 抛出异常时是想应用使用者(用户)传达某种信息
异常跟踪栈
可以用对象的 printStackTrace() 方法用于打印到异常的跟踪栈信息,根据 printStackTrace() 方法的输出结果,可以找到异常的源头。
package com.ittht.day10;
class SelfException extends RuntimeException{
SelfException(){}
SelfException(String msg){
super(msg);
}
}
public class PrintStackTraceTest {
public static void main(String[] args) {
firstMethod();
}
public static void firstMethod(){
secondMethod();
}
public static void secondMethod(){
thirdMethod();
}
public static void thirdMethod(){
throw new SelfException("自定义异常信息");
}
}