我对例外情况有些怀疑。
有人能告诉我为什么java不允许我们在子类中创建Checked Exception,而它允许在子类中使用Unchecked异常
下面exampple throws当我使用'throws IOException'时编译时间错误,但是当我在子类中使用'throws ArithmeticException'时它不会抛出任何错误..我只是想知道它背后的实际原因,你能不能这样做?
以下是代码(您将收到编译时错误)
package com.exception.test;
import java.io.IOException;
public class Parent {
void msg() {
System.out.println("Parent...");
}
public static void main(String[] args) {
Parent parent = new Child();
parent.msg();
}
}
class Child extends Parent {
void msg() throws IOException {
System.out.println("Child...");
}
}
//使用unCheckedException
package com.exception.test;
import java.io.IOException;
public class Parent {
void msg() {
System.out.println("Parent...");
}
public static void main(String[] args) {
Parent parent = new Child();
parent.msg();
}
}
class Child extends Parent {
void msg() throws ArithmeticException {
System.out.println("Child...");
}
}
答案 0 :(得分:5)
如果子类方法声明它可以抛出父级没有的已检查异常,它会破坏Liskov substitution principle,这是面向对象编程的基石之一。
考虑这段代码,声明Child.msg
抛出一个已检查的异常:
void doMsg(Parent p) {
p.msg();
}
如果传入子对象,程序语义会中断,因为现在既未捕获也未抛出已检查的异常:不再“检查”异常。
由于未经检查的异常可以在任何地方抛出,因此声明抛出异常除了文档之外没有任何其他用途。因此可以安全地使用它。
答案 1 :(得分:0)
父类中的msg()
方法可以抛出任何未经检查的异常。因此,如果您明确声明您的孩子抛出未经检查的异常,那么您实际上并未改变合同。您的子方法可能抛出ArithmeticException
,但您的父方法也可能抛出。
答案 2 :(得分:0)
不幸的是,你已经遇到了另一个被称为Checked Exceptions的Java错误的陷阱。您收到的错误是所有Java专业人员都面临的实际问题:您正在实现一个方法,其中包含一些代码,这些代码恰好会抛出一个未由超类方法声明的已检查异常。声明的已检查异常是Java方法签名的一部分;您可以减少子类中的列表,但不能展开它。
如果这只是一个“为什么”的问题,而你需要一个解决方法,那么标准习惯就是
try {
...code that throws the checked exception...
} catch (TheCheckedException e) { throw new RuntimeException(e); }
这称为异常包装。如果你有超过一个或两个未声明的已检查异常,你也可以使用相反的习惯用法,确保所有声明的异常都透明地传播,所有未声明的异常都被包装:
try {
...code that throws various checked exceptions...
}
catch (DeclaredEx1 | DeclaredEx2 | RuntimeException e) { throw e;}
catch (Exception e) { throw new RuntimeException(e); }
答案 3 :(得分:0)
在覆盖时可以缩小已检查的异常,但不能扩大。未经检查的异常不需要被重写的方法
捕获throws子句中指定的已检查异常类是其中的一部分 方法的实现者和用户之间的合同 构造函数。重写方法的throws子句可能未指定 该方法将导致抛出任何已检查的异常 通过其throws子句,不允许重写的方法 抛出。