最近忙的事有点多,断更了几个星期。刚好现在有点时间,就整理了昨天刚学的 Java 中关于异常的知识,内容如下:
目录
一、异常的定义
Java 中的异常( Exception ),指的是 Java 代码发生了各种各样问题的现象。在 Java 中,把异常信息封装成了一个类。当出现了问题时,就会创建异常类对象并抛出与异常相关的信息,如异常出现的位置、原因等。
二、Throwable类
1、基础知识
Throwable 类是 Java 编程语言中所有异常的超类。
它包含了两个直接子类: Error 和 Exception 。
其中,Error表示严重错误,通常是由于系统环境出现问题导致的,例如内存溢出;
而Exception则表示程序运行过程中出现的异常情况,例如输入输出错误、空指针等。
值得一提的是,只有当对象是 Throwable 类(或其子类之一)的实例时,才能通过 Java 虚拟机 或者 Java throw 语句抛出。
2、Throwable 类中的三种方法
(1) getMessage ( ) 方法
getMessage ( ) 方法是返回此 throwable 对象的详细消息字符串。查看上面的运行结果,可以发现打印出来的内容与有参构造函数的参数信息一样,这是因为有参构造函数中的参数就是指定对象的详细消息。
(2) toString ()方法
toString ()方法是此 throwable 对象的简短描述。
(3) printStackTrace () 方法
该方法最常用也最重要。将此 throwable 对象及其追踪输出到指定的 PrintWriter,其实就是打印出原始的出错代码行号和由此引发的出错行号。
三、异常与错误
在 Java 中,程序异常和程序错误是两个不同的概念:
1、程序异常
程序异常是指程序在编译、运行期间发生了某种异常( Exception )必须认真处理。若不处理异常,程序将会结束运行。
2、程序错误
程序错误指程序在运行期间发生了某种错误 (Error)。Error 错误通常没有具体的处理方式,程序将会结束运行。Error 错误的发生往往都是系统级别的问题,都是JVM所在系统发生并反馈给 JVM 的。用户无法针对 Error 进行处理,只能修正代码错误的产生代码如下:
public class Demo(
public static void main (String args)
{
int arr = new int[1024 *1024 *100];
}
这串代码运行时发生了内存溢出错误 OutOfMemoryError,开辟了过大的数组空间,导致JVM在分配数组空间时超出了JVM内存空间,直接发生错误。
四、对异常的处理
讲了这么多,终于到了怎么解决异常这部分了。对于异常的处理,分为两种:捕获处理和抛出处理。
但由于这部分内容较多,篇幅较长,在本篇博客我就浅浅一聊,日后我再更新捕获处理和抛出处理的详细剖析
1、捕获处理
为了避免程序因异常而崩溃,我们需要对其进行捕获和处理。在 Java 中,可以使用 try-catch 语句来实现异常的捕获和处理。其中,try块中包含可能会抛出异常的代码, catch 块则用于捕获并处理这些异常。
2、抛出处理
除了使用 try-catch 语句捕获和处理异常外,还可以使用 throws 关键字将异常抛出给上层调用者。这样做的好处是能够更加灵活地处理异常,但同时也需要注意异常的传递路径和处理方式。
五、异常在重写中的运用
在Java语言中,重写(Override)是指子类覆盖父类的某个方法,并且实现自己特有的行为逻辑。在这个过程中,如果子类方法抛出了异常,那么要注意与父类方法的异常处理相关问题。
具体来说,在 Java 中,子类方法抛出的异常必须是父类方法抛出异常的子集或相等。这种规定是为了确保子类能够保持良好的兼容性,并且不会对使用父类的代码产生影响。
举个例子,我们定义一个 Animal 类,其中包含一个 eat() 方法,该方法声明了一个受检查异常 IOException:
public class Animal
{ public void eat() throws IOException
{
// ...
}
}
现在,我们定义一个 Cat 类,它继承于 Animal 类,并且重写了 eat() 方法,但是并没有抛出任何异常:
public class Cat extends Animal
{
@Override
public void eat()
{
// ...
}
}
这样做是没有问题的,因为子类的异常类型为空,也就是说它是父类异常类型的子集。
但是,如果我们在 Cat 类的 eat() 方法中抛出了 Exception 异常,那么编译器就会提示错误,因为 Exception 不是 IOException 的子类:
public class Cat extends Animal
{
@Override
public void eat() throws Exception
{ // 编译错误
// ...
}
}
针对这种情况,我们有两种解决方法:
- 不抛出任何异常。如果子类的实现不需要抛出异常,则可以像上面的例子一样省略 throws 子句。
- 抛出与父类相同的异常。如果子类的实现确实需要抛出异常,那么就应该抛出与父类相同的异常类型。
总之,在重写方法时,要注意异常类型的继承关系,遵循 “子类重写的方法抛出的异常类型必须是父类方法抛出异常类型的子集或相等” 的规则,从而确保代码的良好兼容性和可维护性。