CodeGym /Java 博客 /随机的 /Java 中的异常
John Squirrels
第 41 级
San Francisco

Java 中的异常

已在 随机的 群组中发布
你好!在今天的课程中,我们将讨论 Java 异常。日常生活充满了我们意想不到的情况。例如,您早上起床寻找手机充电器,但到处都找不到。你去洗手间洗澡才发现水管都结冰了。你上了车,但它无法启动。人类能够很容易地应对这种不可预见的情况。在本文中,我们将尝试弄清楚 Java 程序如何处理它们。

什么是 Java 异常?

在编程世界中,程序执行中的错误和不可预见的情况被称为异常。在程序中,异常可能由于无效的用户操作、磁盘空间不足或与服务器的网络连接丢失而发生。编程错误或 API 的不正确使用也可能导致异常。与现实世界中的人类不同,程序必须确切地知道如何处理这些情况。为此,Java 有一种称为异常处理的机制。

关于关键字的几句话

Java中的异常处理是基于在程序中使用以下关键字:
  • try - 定义一个可能发生异常的代码块;
  • catch - 定义处理异常的代码块;
  • finally - 定义一个可选的代码块,如果存在,则无论 try 块的结果如何都会执行。
这些关键字用于在代码中创建特殊结构:try{}catchtry{}catch{}finallytry{}finally{}
  • throw - 用于引发异常;
  • throws - 在方法签名中用于警告该方法可能会抛出异常。
在 Java 程序中使用关键字的例子:

// This method reads a string from the keyboard

public String input() throws MyException { // Use throws to warn 
// that the method may throw a MyException
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
// We use a try block to wrap code that might create an exception. In this case,
// the compiler tells us that the readLine() method in the 
// BufferedReader class might throw an I/O exception
    try {
        s = reader.readLine();
// We use a catch block to wrap the code that handles an IOException  
    } catch (IOException e) {
        System.out.println(e.getMessage());
// We close the read stream in the finally block
    } finally {
// An exception might occur when we close the stream if, for example, the stream was not open, so we wrap the code in a try block
        try {
            reader.close();
// Handle exceptions when closing the read stream
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    if (s.equals("")) {
// We've decided that an empty string will prevent our program from working properly. For example, we use the result of this method to call the substring(1, 2) method. Accordingly, we have to interrupt the program by using throw to generate our own MyException exception type.
        throw new MyException("The string cannot be empty!");
    }
    return s;
}

为什么我们需要例外?

让我们看一个来自现实世界的例子。想象一下,一段高速公路有一座承载能力有限的小桥。如果一辆比桥的极限重的汽车驶过它,它可能会倒塌。温和地说,驾驶员的情况将变得异常。为避免这种情况,交通部门会在出现问题之前在道路上安装警告标志。看到警告标志,司机将他或她的车辆重量与桥梁的最大重量进行比较。如果车辆太重,司机会绕道行驶。交通部门一是允许卡车司机在必要时改变路线,二是警告司机注意主干道上的危险,三是警告司机在某些情况下不得使用这座桥。 Java 中的异常 - 2能够防止和解决程序中的异常情况,使其继续运行,这是在 Java 中使用异常的原因之一。异常机制还允许您通过验证(检查)任何输入来保护您的代码 (API) 免遭不当使用。现在假设您是交通部门。首先,您需要知道驾车者可能会遇到麻烦的地方。其次,您需要创建和安装警告标志。最后,如果主要路线出现问题,您需要绕行。在 Java 中,异常机制以类似的方式工作。在开发过程中,我们使用try块围绕代码的危险部分构建“异常屏障”,我们使用 catch {}提供“备用路由”块,我们在finally{}块中编写无论如何都应该运行的代码。如果我们不能提供“备用路线”或者我们想给用户选择的权利,我们至少要警告他或她危险。为什么?试想一下,一个司机在没有看到任何警告标志的情况下,到达一座他无法通过的小桥时的愤慨!在编程中,当编写我们的类和方法时,我们不能总是预见到它们可能会被其他开发人员如何使用。因此,我们无法预见 100% 正确的解决异常情况的方法。也就是说,警告其他人可能出现异常情况是一种很好的形式。Java 的异常机制让我们可以通过throws来做到这一点关键字——本质上是一个声明,表明我们的方法的一般行为包括抛出异常。因此,任何使用该方法的人都知道他或她应该编写代码来处理异常。

警告别人“麻烦”

如果您不打算在您的方法中处理异常,但想警告其他人可能会发生异常,请使用throws关键字。方法签名中的 this 关键字意味着,在某些情况下,该方法可能会抛出异常。此警告是方法接口的一部分,并允许其用户实现自己的异常处理逻辑。在 throws 之后,我们指定抛出的异常类型。这些通常派生自 Java 的Exception类。由于 Java 是一种面向对象的语言,因此所有异常都是 Java 中的对象。 Java 中的异常 - 3

异常层次结构

当程序运行时发生错误时,JVM 从 Java 异常层次结构中创建一个适当类型的对象——一组可能的异常,它们来自一个共同的祖先——Throwable。我们可以将异常的运行时情况分为两组:
  1. 程序无法恢复并继续正常运行的情况。
  2. 可以恢复的情况。
第一组包括涉及从Error类派生的异常的情况。这些是由于 JVM 故障、内存溢出或系统故障而发生的错误。它们通常表示无法通过软件修复的严重问题。在 Java 中,编译器不检查此类异常的可能性,因此称为未检查异常。该组还包括 RuntimeExceptions,它们是从Exception派生的异常类,由 JVM 在运行时生成。它们通常是由编程错误引起的。这些异常在编译时也不会被检查(未检查),因此您不需要编写代码来处理它们。第二组包括在您编写程序时可以预见的异常情况(因此您应该编写代码来处理它们)。此类异常称为已检查异常。说到异常,Java 开发人员的大部分工作就是处理这种情况。

创建异常

当程序运行时,JVM 或手动使用throw语句生成异常。发生这种情况时,会在内存中创建一个异常对象,程序的主流程被打断,JVM 的异常处理程序会尝试处理该异常。

异常处理

在 Java 中,我们创建代码块,在其中使用try{}catchtry{}catch{}finallytry{}finally{}结构 预测异常处理的需要。当tryJava 中的异常 - 4块中抛出异常时,JVM 会在下一个catch块中寻找合适的异常处理程序。如果catch块具有所需的异常处理程序,则将控制权传递给它。如果没有,则 JVM 会在catch块链中向下查找,直到找到合适的处理程序。执行catch块后,控制权将转移到可选的finally块。如果一个合适的捕获没有找到块,然后 JVM 停止程序并显示堆栈跟踪(当前方法调用堆栈),如果它存在,则首先执行finally块。异常处理示例:

public class Print {

     void print(String s) {
        if (s == null) {
            throw new NullPointerException("Exception: s is null!");
        }
        System.out.println("Inside print method: " + s);
    }

    public static void main(String[] args) {
        Print print = new Print();
        List list= Arrays.asList("first step", null, "second step");

        for (String s : list) {
            try {
                print.print(s);
            }
            catch (NullPointerException e) {
                System.out.println(e.getMessage());
                System.out.println("Exception handled. The program will continue");
            }
            finally {
                System.out.println("Inside finally block");
            }
            System.out.println("The program is running...");
            System.out.println("-----------------");
        }

    }
    }
以下是主要方法 的结果:

Inside print method: first step
Inside finally block
The program is running...
-----------------
Exception: s is null!
Exception handled. The program will continue
Inside finally block
The program is running...
-----------------
Inside print method: second step
Inside finally block
The program is running...
-----------------
finally通常用于关闭任何流并释放在try块中打开/分配任何资源。然而,在编写程序时,并不总是能够跟踪所有资源的关闭情况。为了让我们的生活更轻松,Java 的开发人员提供了try-with-resources结构,它会自动关闭在try块中打开的任何资源。我们的第一个例子可以用try-with-resources重写:

public String input() throws MyException {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
        s = reader.readLine();
   } catch (IOException e) {
       System.out.println(e.getMessage());
   }
    if (s.equals("")) {
        throw new MyException ("The string cannot be empty!");
    }
    return s;
}
得益于 Java 7 版本引入的能力,我们还可以将捕获异构异常合并到一个块中,使代码更加紧凑和可读。例子:

public String input() {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
        s = reader.readLine();
        if (s.equals("")) {
            throw new MyException("The string cannot be empty!");
        }
    } catch (IOException | MyException e) {
        System.out.println(e.getMessage());
    }
    return s;
}

底线

在 Java 中使用异常可以让您通过创建“备份路由”使程序更健壮,使用 catch 块将主要代码与异常处理代码分开,并使用 throws 将异常处理的责任转移给使用您的方法的任何
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION