是否可以告诉编译器方法总是抛出异常

时间:2013-02-22 08:15:53

标签: java

一般来说,Java编译器不会传播方法“总是”抛出异常的信息,因此不会检测到所有代码路径都已完成。

(这是因为Java编译器独立编译每个类。)

当你想写这样的东西时,这是一个问题。

public class ErrorContext {
    public void fatalISE(String message) {
        String context = "gather lots of information about the context of the error";
        throw new IllegalStateException(context +": " + message);
    }
}

public class A {
    public MyObject myMethod() {
        if (allIsGood()) {
            return new MyObject();
        }
        ErrorContext.fatalISE("all is not good");
    }
}

(即一种收集上下文信息的“断言助手”)。

因为编译器会抱怨myMethod并不总是返回MyObject。

据我所知,没有特定的注释来指示方法总是抛出。

6 个答案:

答案 0 :(得分:35)

一个简单的解决方法是让你的fatalISE方法不抛出异常,但只创建它:

public class ErrorContext {
    public IllegalStateException fatalISE(String message) {
        String context = "gather lots of information about the context of the error";
        return new IllegalStateException(context +": " + message);
    }
}

public class A {
    public MyObject myMethod() {
        if (allIsGood()) {
            return new MyObject();
        }
        throw ErrorContext.fatalISE("all is not good");
    }
}

这样编译器就会知道不要抱怨丢失return。忘记使用throw是不太可能的,因为编译器通常会抱怨。

答案 1 :(得分:8)

我使用的技巧是替换

public void fatalISE(String message) {
    String context = "gather lots of information about the context of the error";
    throw new IllegalStateException(context +": " + message);
}

public <T> T fatalISE(String message) {
    String context = "gather lots of information about the context of the error";
    throw new IllegalStateException(context +": " + message);
}

然后,在myMethod中,使用:

public MyObject myMethod() {
   if (allIsGood()) {
        return new MyObject();
    }
    return ErrorContext.fatalISE("all is not good");
}

它将适用于myMethod的返回类型,包括基本类型。您仍然可以在void方法中使用fatalISE,只需不使用return关键字。

答案 2 :(得分:6)

如何扭转if条件?

public MyObject myMethod() {
    if (!allIsGood()) {
        ErrorContext.fatalISE("all is not good");
    }
    return new MyObject();
}
祝你好运!

答案 3 :(得分:5)

添加

return null;

最后。 (无论如何它永远不会到达那里,但这应该是编译器的沉默)

答案 4 :(得分:1)

您要尝试做的是声明一个函数永不返回,这是Java不知道该怎么做的。 Kotlin, for contrast, has a Nothing type。如果您声明函数返回“ Nothing”,则表示它永不返回。

Zorglub在上面的回答中,函数返回类型参数“ T”的类型参数是您在Java中最接近的。这是我最近写的东西,它记录一个字符串,然后使用相同的字符串引发异常:

/**
 * Error logging. Logs the message and then throws a {@link RuntimeException} with the given
 * string.
 *
 * @param tag String indicating which code is responsible for the log message
 * @param msg String or object to be logged
 */
@CanIgnoreReturnValue
@SuppressWarnings("TypeParameterUnusedInFormals")
public static <T> T logAndThrow(String tag, Object msg) {
    String s = msg.toString();
    Log.e(tag, s);
    throw new RuntimeException(s);
}

此代码使用Android的标准日志记录API,是我希望能够在可能需要值的任何地方使用的代码。我希望能够有一个lambda,其主体只是对此函数的调用。该解决方案效果很好,但是值得解释一些棘手的地方:

  • 您不能在需要Java基本类型(int,double,boolean等)的地方执行此操作。
  • 如果您使用的是error-prone(一种出色的静态Java错误检查工具),则必须使用两个@注释,因为否则它将在调用站点上抱怨您未使用返回值,并且它将在方法定义中抱怨您使用类型参数在做不可言喻的邪恶事情。

答案 5 :(得分:0)

我刚刚遇到了这个用例,但是使用的方法应该总是抛出2种或更多类型的异常。

要编译代码,您可以添加return null;作为MouseEvent表示。

或更好地将其替换为throw new AssertionError(),以防止返回空值,提高可读性并确保如果有人修改checkAndAlwaysThrowException(),它将继续始终抛出异常

public Object myMehtod() throws ExceptionType1, ExceptionType2 {
    //....
    checkAndAlwaysThrowException();
    throw new AssertionError("checkAndAlwaysThrowException should have throw exception");
}

public void checkAndAlwaysThrowException() throws ExceptionType1, ExceptionType2 {
    if (cond) {
        throw new ExceptionType1();
    } else {
        throw new ExceptionType2();
    }
}