有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java为什么抛出方法签名的一部分

为什么方法上的throws是其签名的一部分?把它包括在内似乎很奇怪。下面是一个例子,它阻碍了:

@Overide
public void foo() {
    throw new UnsupportedOperationException();
}

如果有人从外部看到这个方法,他们可能会在不知道它不受支持的情况下尝试使用它。他们只会在尝试运行代码时学习

但是,如果他们可以这样做,他们会通过查看该方法知道它不受支持,并且如果UnsupportedOperationException没有扩展RuntimeException,他们将得到编译错误。EDIT1:但这是不可能的,因为throws是签名的一部分,所以重写将不起作用

@Overide
public void foo() throws UnsupportedOperationException {
    throw new UnsupportedOperationException();
}

这个问题与Java的设计有关,所以我知道如果没有一个研究Java的人来回答这个问题,可能很难回答,但我希望这个问题以前有人问过他们,或者有一个明显的理由用这种方式来解释原因


共 (3) 个答案

  1. # 1 楼答案

    throws部分并不表示抛出所述异常需要该方法,即使在特定情况下也是如此。它只告诉函数允许这样做

    因此,包含throws UnsupportedOperationException并不意味着该方法不受支持。除此之外UnsupportedOperationException是一个RuntimeException,所以一个方法可以throw不管怎样

    现在,出于在方法签名中需要它的原因,它可以归结为检查异常的能力。为了让编译器能够决定一个方法是否只能抛出指定的异常,它必须能够决定它调用的方法不能抛出未捕获的异常

    例如,这意味着重写一个方法意味着您不能添加可能抛出的异常,否则您将无法验证调用该方法的方法不能抛出它指定以外的任何异常。另一种方法是可能的(但我不确定Java是否支持),用可能不会抛出的方法覆盖可能抛出的方法

    例如:

    class B {
        int fubar(int) throws ExceptionA {
        }
    
        int frob(int) throws ExceptionA {
             return fubar(int);
        }
    }
    
    class D extends B {
        int fubar(int) throws ExceptionB {
        }
    }
        
    

    现在frob被指定为可能仅throw{},但在调用this.fubar时,可能会抛出其他内容,但fubar被定义为可能仅throw{}。这就是为什么D.fubar是一个无效的重写,因为这将打开this.fubar实际抛出ExceptionB的可能性,并且编译器无法保证frob不会抛出ExceptionB

  2. # 2 楼答案

    没有人提到的一件事是对你的问题的一个非常重要的回答:

    Why throws, on a method, is part of its signature?

    throws不是方法签名的一部分

    JLS 8.4.2. Method Signature非常清楚地表明:

    Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the type parameters of M, the same formal parameter types.


    If anyone were to see this method from the outside, they might try to use it without knowing that it is not supported.

    这正是throws设计为在编译时检查所有检查异常的主要原因-该方法的客户端将知道该方法可能抛出什么


    检查异常被强制处理或指定抛出(但此规范不是方法签名的一部分)

    未检查的异常不必处理或指定抛出,而且Oracle's tutorial善于解释原因:

    Runtime exceptions represent problems that are the result of a programming problem, and as such, the API client code cannot reasonably be expected to recover from them or to handle them in any way. Such problems include arithmetic exceptions, such as dividing by zero; pointer exceptions, such as trying to access an object through a null reference; and indexing exceptions, such as attempting to access an array element through an index that is too large or too small.

  3. # 3 楼答案

    Java has two different types of exceptions: checked Exceptions and unchecked Exceptions.

    未检查的异常是RuntimeException的子类,您不必添加抛出声明。所有其他异常都必须在方法体中处理,要么使用try/catch语句,要么使用throws声明

    未检查异常的示例:IllegalArgumentException,有时用于通知使用非法参数调用了方法。不需要投掷

    检查异常的示例:IOException来自java的一些方法。io包可能会抛出。对方法声明使用try/catch或add抛出IOException,并将异常处理委托给方法调用方