《疯狂Java讲义》读书笔记6

数据结构,对循环队列,双端队列的总结:

http://t.csdn.cn/kgZcI

刷题:

http://t.csdn.cn/YMc3M

异常处理

对于构造大型、健壮、可维护的应用,错误处理是整个应用要考虑的重要方面。

在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("自定义异常信息");
    }
}

你可能感兴趣的:(Java,java,servlet,开发语言)