学习笔记11(异常)

1、异常简介

在Java程序运行时,可能会发生许多错误情况,导致程序停止执行。异常是由于错误或意外事件发生而在内存中生成的对象。当生成一个异常时,它需要被“抛出”,除非程序检测到异常并进行处理,否则异常就会导致应用程序停止。

要检测到抛出的异常并阻止异常终止程序,就需要创建异常处理程序。异常处理程序是在抛出异常时响应异常的代码,拦截和响应异常的过程称为异常处理。如果代码在抛出时不处理异常,则默认的异常处理程序将处理它,默认的异常处理程序会打印错误消息并导致程序崩溃。

public class BadArray
{
    public static void main(String[] args)
    {
        // Create an array with 3 elements.
        int[] numbers = { 1, 2, 3 };

        // Attempt to read beyond the bounds
        // of the array.
        for (int i = 0; i <= 3; i++)
            System.out.println(numbers[i]);
    }
}
1
2
3
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at BadArray.main(BadArray.java:15)

so,java异常时一个对象。异常对象是从JavaAPI中的类中创建的。该API具有广泛的异常类层次结构。

所有的异常类都来自于ErrorException类。从Error中继承的类是指当发生严重错误时抛出的异常,例如JVM中的内部错误或内存耗尽。程序不应尝试处理这些错误,你也处理不了这些错误。我们应该处理的异常应该继承自Exception类。Exception里的子类也是更细的异常的超类。比如IOException表示于输入和输出操作相关的异常。RuntimeException表示编程错误导致的异常的超类,例如数组下标越界。

2、处理异常

如果想处理异常,我们就需要用到try语句。

try
{
 (try block statements . . . ) }
catch (ExceptionType parameterName) {
 (catch block statements . . . ) }

 首先,关键字try出现。接下来是大括号。大括号中会有一个必需的代码块。这个代码块被称为try blocktry block是正在执行的一个或多个语句,并且可能会抛出异常。你可以认为try block中的代码是“受保护的”,因为如果try block抛出异常,应用程序将不会停止。

try block之后,将出现一个catch子句。catch语句以关键字catch开头,后面是括号,括号里是异常的类型和名字。这里实际上是一个变量声明,如果try block中的代码抛出某个异常类型的异常,则这里声明的变量将引用try中抛出的异常对象。此外,try中的语句在遇到异常的时候将会立即跳出,还会立即执行catch语句后面的代码。catch语句后面的代码称为catch block,同样需要大括号。

让我们看一个例子:

try
{
 File file = new File("MyFile.txt");
 Scanner inputFile = new Scanner(file);
}
catch (FileNotFoundException e)
{
 System.out.println("File not found.");
}

 首先,执行try block中的代码。如果此代码抛出异常,则JVM将搜索可以处理异常的catch子句。为了使catch语句能够处理异常,catch后括号中的参数必须与异常类型兼容。

此catch语句声明了一个名为e的变量作为其参数。e变量可以引用FileNotFound异常类的对象。因此,这个catch子句可以处理FileNotFound类的异常。如果try block中的代码抛出FileNotFound异常,则e变量将引用异常对象,并将执行try block中的代码。在本例中,会打印“File not found”。执行try block后,程序将继续执行try/catch语句之后出现的代码。

下图说明了出现异常及不出现异常时的状况:

在catch语句中,也可以使用多态的特性,比如接下来的例子:

try
{
 number = Integer.parseInt(str);
}
catch (Exception e)
{
 System.out.println("Conversion error: " +
 e.getMessage());
}

虽然e实际上是一个NumberFormatException类的错误,但是所有的类都继承自Exception类,所以在这里使用Exception类来引用是完全没问题的。

3、返回默认的错误信息  

 每个异常类的对象都有一个getMessage方法,这个方法可以返回默认的错误信息,也就是当程序报错的时候在控制台输出的语句,看下面的例子:

/**
 This program causes an error and crashes.
 */

import java.io.*; // For file I/O classes
        import java.util.Scanner; // For the Scanner class
        import javax.swing.JOptionPane; // For the JOptionPane class

/**
 This program demonstrates how a FileNotFoundException
 exception can be handled.
 */

public class ExceptionMessage
{
    public static void main(String[] args)
    {
        File file; // For file input
        Scanner inputFile; // For file input
        String fileName; // To hold a file name

        // Get a file name from the user.
        fileName = JOptionPane.showInputDialog("Enter " +
                "the name of a file:");

        // Attempt to open the file.
        try
        {
            file = new File(fileName);
            inputFile = new Scanner(file);
            JOptionPane.showMessageDialog(null,
                    "The file was found.");
        }
        catch (FileNotFoundException e)
        {
            JOptionPane.showMessageDialog(null, e.getMessage());
        }

        JOptionPane.showMessageDialog(null, "Done.");
        System.exit(0);
    }
}

如果用户输入了一个不存在的文件名,程序就会报错并返回错误信息。 

4、尝试捕获多个异常

(1)如何捕捉多个异常

有的时候一个try语句会抛出多个异常(在程序执行一遍的时候,只要抓到一个异常就不会继续执行,并不会有抛出第二个异常的机会。但是在多次执行的时候,可能对于第一个对象抛出这个异常,对于第二个对象抛出那个异常,也就是说在程序复用的过程中,一个try语句两次抛出的异常可能不是一个种类),那么我们就需要用不同的catch语句来处理不同的异常。

 import java.io.*; // For File class and FileNotFoundException
         import java.util.*; // For Scanner and InputMismatchException
         import javax.swing.JOptionPane; // For the JOptionPane class

/**
 This program demonstrates how multiple exceptions can
 be caught with one try statement.
 */

public class SalesReport
{
    public static void main(String[] args)
    {
        String filename = "SalesData.txt"; // File name
        int months = 0; // Month counter
        double oneMonth; // One month's sales
        double totalSales = 0.0; // Total sales
        double averageSales; // Average sales

        try
        {
            // Open the file.
            File file = new File(filename);
            Scanner inputFile = new Scanner(file);

            // Process the contents of the file.
            while (inputFile.hasNext())
            {
                // Get a month's sales amount.
                oneMonth = inputFile.nextDouble();

                // Accumulate the amount.
                totalSales += oneMonth;

                // Increment the month counter
                months++;
            }

            // Close the file.
            inputFile.close();

            // Calculate the average.
            averageSales = totalSales / months;

            // Display the results.
            JOptionPane.showMessageDialog(null,
                    String.format("Number of months: %d\n" +
                                    "Total Sales: $%,.2f\n" +
                                    "Average Sales: $%,.2f",
                            months, totalSales, averageSales));
        }
        catch(FileNotFoundException e)
        {
            // Thrown by the Scanner constructor when
            // the file is not found.
            JOptionPane.showMessageDialog(null,
                    "The file " + filename + " does not exist.");
        }
        catch(InputMismatchException e)
        {
            // Thrown by the Scanner class's nextDouble
            // method when a non-numeric value is found.
            JOptionPane.showMessageDialog(null,
                    "Non-numeric data found in the file.");
        }

        System.exit(0);
    }
}

 Scanner类的构造器可能抛出FileNotFoundException异常,nextDouble方法又有可能抛出InputMismatchException异常(在java.util里),所以这里的catch语句有两个用来处理这两个可能的异常。

当然我们也可以使用一个try语句来捕获多个异常,在java7中,java引入了这个新的特性。这可以减少需要捕获多个异常的尝试语句中的大量重复代码,但要缺点是只能对每个异常执行相同的操作。

try
{
 (try block statements . . . ) }
catch(NumberFormatException ex)
{
 respondToError();
}
catch(IOException ex)
{
 respondToError();
}

对两种不同的异常,执行的操作相同,那么我们就可以把这段代码改写成这样:

try
{
 (try block statements . . . ) }
catch(NumberFormatException | IOException ex)
{
 respondToError();
}

请注意,在catch语句中,异常类型由一个“|”符号分隔,该符号与用于逻辑OR操作符的符号相同。你可以认为这个语句将抓住NumberFormatExceptionIOException

(2)多异常的捕捉顺序

对于一个try语句中的特定的一种类型的异常,我们只能为之匹配一个catch语句,如果为一种异常写了多个语句,程序就会报错。

try
{
 number = Integer.parseInt(str);
}
catch (NumberFormatException e)
{
 System.out.println("Bad number format.");
}
// ERROR!!! NumberFormatException has already been caught!
catch (NumberFormatException e)
{
 System.out.println(str + " is not a number.");
}

有时候,这种异常也会由多态性导致:

try
{
 number = Integer.parseInt(str);
}
catch (IllegalArgumentException e)
{
 System.out.println("Bad number format.");
}
// This will also cause an error.
catch (NumberFormatException e)
{
 System.out.println(str + " is not a number.");
}

 因为NumberFormatExceptionIllegalArgumentException,所以当catch抓到一个NumberFormatException异常的时候,会先匹配第一个catch。所以我们应该把更具体的异常写在考前的异常语句中。如果catch(exception e)写在第一个异常中,那么不论什么类型的异常,都会匹配到这个catch语句中,因为exception是所有异常的父类,由多态性可知,所有异常都可以是excrption类型的变量)。下面是异常类的继承关系:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值