Java 如果我知道永远不会抛出异常,为什么我必须声明它?

Java 如果我知道永远不会抛出异常,为什么我必须声明它?,java,exception,Java,Exception,假设我有一个为某个输入声明异常的函数,我用保证不会抛出异常的输入调用它。编译器强制我声明或捕获第二个函数的异常,即使我确定不会抛出它。有什么办法可以避免申报吗?如果没有,为什么没有?如果答案是因为这是一个坏主意,为什么这是一个坏主意 公共类Foo{ 私人int n; public Foo(int n)抛出否定枚举异常{ 如果(n

假设我有一个为某个输入声明异常的函数,我用保证不会抛出异常的输入调用它。编译器强制我声明或捕获第二个函数的异常,即使我确定不会抛出它。有什么办法可以避免申报吗?如果没有,为什么没有?如果答案是因为这是一个坏主意,为什么这是一个坏主意

公共类Foo{
私人int n;
public Foo(int n)抛出否定枚举异常{
如果(n<0)抛出新的NegativeEnumberException;
这个,n=n;
}
public Foo square(){//为什么我必须声明EnumberException
返回新的Foo(n*n);
}
}

编辑:我知道我可以使我的异常完全不需要声明,但我确实希望它在一般情况下被声明,只是不希望在我知道它不会被抛出的情况下被声明。

Java检查异常旨在提供硬保证。选中异常的“throws”子句是接口约定

您显然在问代码如何保证不会使硬保证失效

在语言中具有这样一个特性似乎与首先检查异常是不一致的

对我来说,数据类型问题似乎很相似。考虑

  void func(int n) {
       char c = int n;
  }
编译器反对缩小范围。“但我保证n<128”。对不起,不够好。您需要编写经批准的处理方法,即强制转换表达式。类似地,对于已检查的异常,您需要编写一种经批准的处理方法,例如catch子句。

因此,在square()中(调用方函数),您正在调用Foo(int)(调用函数),Foo(int)可能会引发异常。从函数中抛出异常的目的是在调用函数中处理它,否则该异常不会得到处理,应用程序可能会崩溃。 因此,在这种情况下,您有两种选择:

1-使用try-catch处理调用方函数中引发的异常

2-再次从调用方函数抛出此异常,因此现在处理此抛出错误的责任在于调用square()函数的函数


无论如何,声明一个可能引发异常但不在调用函数中处理此潜在异常的函数是错误的。

类型系统不理解n*n是肯定的

您可能能够在类型系统中对您所知道的域属性进行建模,以使代码更安全,请参见下面的玩具示例

class Number {
    int n;
    public Number(int n) {
        this.n = n;
    }
    Number add(Number a) {
        return new Number(n + a.n);
    }

    static PositiveNumber square(Number n) {
        return new PositiveNumber(n.n * n.n);
    }
}

class PositiveNumber extends Number {

    public PositiveNumber(int n) {
        super(n);
    }
    
    PositiveNumber add(PositiveNumber a) {
        return new PositiveNumber(a.n + n);
    }
}

public class Main
{
    static void foo(PositiveNumber n) {
    }
    
    public static void main(String[] args){
        PositiveNumber a = new PositiveNumber(1);
        PositiveNumber b = new PositiveNumber(2);
        Number c = new Number(-1);
        foo(a.add(b)); // ok, adding two positive numbers is always positive
        foo(a.add(c)); // fails to type check
        foo(Number.square(c)); // ok, squaring a number is always positive
    }
}

n<0
是合同的一部分或实施细节时,
Foo
将抛出异常,这是事实吗?这是一条重要的信息,将决定您在这里应该做什么。编译器如何知道您不会调用
new Foo(-19)
?而且,
n*n
也不总是积极的。考虑一下它溢出的情况。“清扫车够公平的,但那只是一个兆头。”例如,考虑一种方法,它返回自己的拷贝,因为语言是这样设计的。如果您不想强制用户捕获或重试,请不要声明异常。请注意,C#和Kotlin这两种较新的语言都排除了检查异常,因为回顾过去,它们被广泛认为是设计错误。如果您知道不会抛出异常,请使用try/catch。