抛出异常的要点

The point of throwing exceptions

抛出异常有什么意义? 例如我偶然发现了这个:

static List<Integer> list(int [] a) {
    if (a == null)
        throw new NullPointerException();
        //...

但是当你不抛出空指针的时候,你也会得到一个空指针? 我经常看到这个,我想知道这是否是一个值得学习的好习惯?

THROW 背后的想法是防止错误停止您的程序。

如果这是一个足够致命的错误,您的程序无论如何都会停止。但如果程序可以继续,它会继续,并且只是让您知道发生了错误。

在很多情况下,你分配一个函数来报告错误,因为你把它扔了并且知道它是什么。

我总是发现抛出异常是设计和可读性的问题。例如,通常当我设计一些东西时,我更喜欢在出现错误的地方处理错误。然而,一个同样有效的设计是抛出异常并在其他地方处理它。我已经看到一些抽象,其中通常您的流程与此类似...

FlowControl -> GenericMethod(仅捕获异常和调用方法)-> PrivateMethods (一般用来做作业,抛出异常)。

您可能还会在这里找到更完整的答案:When to catch the Exception vs When to throw the Exceptions?

如果您使用空指针,您的方法的其余部分可能不会抛出异常,而是会产生某种不良行为。在你的例子中,如果它基本上是一个 "ToList" 包装器,它可能被实现为:

static List<Integer> list(int[] a)
{
    List<int> ret = new List<int>();
    foreach (int i in a)
        ret.add(i);
    return ret;
}

这将只是 return 一个空列表,而不是抛出(如果我没记错的话,我认为 C# 不会抛出 foreach 中使用的空列表)。因此,您需要包括显式空检查和 throw 以获得您想要的行为。

抛出特定异常意味着您的应用程序遇到了不应该遇到的问题。它可以是无效参数(当有人传递 null 并且当前方法不能使用 null 值时),无效字段状态(其值已更改为某个值,例如当前状态是禁止的)等等。

基本上,当您以良好的方式抛出异常时,每个使用您的例如图书馆可以保持其正确的流程。

最好快速失败。例如,该函数甚至可以在引用示例中的变量 "a" 之前做很多事情,从而导致大量不必要的处理。如果您知道 "a" 是,最好立即失败从一开始就为空。您也可以将自定义错误消息附加到异常。