【问题标题】:Can I use throws in constructor?我可以在构造函数中使用 throws 吗?
【发布时间】:2010-12-19 21:15:52
【问题描述】:

我必须在构造函数中初始化文件对象并处理异常,使用throws 是否有效还是应该使用try/catch

【问题讨论】:

标签: java exception


【解决方案1】:

在构造函数中抛出异常是可以的。我知道一些 Java 库类是这样做的(URI 只是一个例子)。我认为抛出异常比返回未知或无效状态的对象要好。

【讨论】:

  • URL 类除了糟糕的代码外,并不是一个很好的例子。例如,它的equals 方法将根据您是否连接到互联网等返回不同的值。(只是一方面,您的答案很好)
  • @abyx:既然你提到了它,我完全同意 URL。我将答案更改为使用 URI 作为示例。谢谢。
  • URI/URL 需要注意的一点是,如果你输入错误的输入会引发异常,而不是因为幕后发生的事情(比如无法打开文件,或者它是 DNS 查找,无论如何)
  • @Chad:没有太大区别。由于无法创建有效对象而引发异常。
  • 我很失望这是答案,因为我认为在构造函数中抛出异常是不好的设计。所以对于其他阅读这篇文章的人来说,不要!而是重新设计您的课程。
【解决方案2】:

我认为在构造函数中抛出异常是一种优雅的方式来指示构造函数内部的错误情况。否则,您将不得不创建另一个初始化资源的函数,并在构造对象后调用该函数。

【讨论】:

    【解决方案3】:

    当然可以,并且抛出异常实际上是我会做的(而不是在构造函数中吞下它)。您想让调用者知道发生了意外的事情,您不想返回未正确初始化的实例。也就是说,可能表明你在构造函数中做了太多事情。

    【讨论】:

    • +1 来弥补这一点。不发表评论就不能投票。
    • @BalusC 那确实不错。
    【解决方案4】:

    考虑一个构造函数,或者任何方法,都有一个契约。构造函数的约定非常简单——你给我(零个、一个或多个)参数,我会给你一个构造对象。好的做法是建议这个对象应该正确初始化其内部数据结构并保持不变,尽管语言本身并没有强制执行这一点。

    如果由于某种原因构造函数不能遵守这个契约,那么它应该抛出一个异常。这可能是因为传递的参数(如果有)不可接受(前提条件失败)或某些外部问题(文件系统已满、堆耗尽、网络中断等)阻止了它。

    【讨论】:

      【解决方案5】:

      对我来说,这不是效率问题。

      如果您可以对异常状态做出反应并且仍然创建有效或至少可用的对象,则在构造函数中处理它。

      否则 - 如果对象不可用 - 将异常返回给调用者。在这种情况下,他将无法获得对象并且无法继续处理不可用/不一致的实例,这可能会在应用程序的其他一些角落产生错误。

      【讨论】:

        【解决方案6】:

        您当然可以(例如,FileOutputStream 可以)。

        应该明智地从构造函数中抛出异常 - 确保自己清理干净。有时会在构造函数中抛出异常以确保 RAII 被持有。

        【讨论】:

          【解决方案7】:

          一般来说,在构造函数中只包含简单的逻辑是个好主意(例如,使用参数值设置私有字段)。并使用其他特殊的“组装者”、“准备者”或“工厂”设置您的对象。 get/set 方法也是如此——它们应该尽可能简单。

          当然可以从构造函数中抛出异常。但这不是一个好习惯。

          【讨论】:

          • 构造函数应该让对象处于可用和一致的状态,不管它必须做什么。如果它不能,无论出于何种原因,它都需要发出信号。返回某种错误代码是在询问错误,而另一种选择是抛出异常。
          • 那又怎样?我的意思是,在大多数情况下,构造函数不应该尝试执行任何可能失败的操作。
          【解决方案8】:

          我建议尝试/捕获,并从捕获中抛出有用的错误。这将使用户更好地了解您的应用程序出了什么问题。例如,您应该检查文件是否存在以及格式是否正确。

          【讨论】:

            【解决方案9】:

            您应该在构造函数中将对象置于安全状态,但假设您要打开一个不存在的文件(用于读取),抛出异常是唯一的方法。所以这取决于你实现的逻辑

            【讨论】:

            • 为什么不在构造函数中打开一个文件,特别是如果你的对象是用来操作那个文件的?
            • 是的,点 glen,我的对象将适用于我将在构造函数中打开它的文件
            • @i2ijeya,如果您的对象在没有文件的情况下无法运行,则从构造函数中抛出异常。这是Java中一种合法且易于理解的模式。请参阅其他人发布的 FileInputStream 示例。
            【解决方案10】:

            当然,它实际上在 Java 中被大量使用。例如,

            public FileInputStream(String name)
                            throws FileNotFoundException
            

            【讨论】:

              【解决方案11】:

              一般来说,在构造函数中做繁重的工作是个坏主意:在许多语言中,无论如何,在构造过程中可以对异常做些什么都会受到限制。

              【讨论】:

              • 你是说由于其他语言的限制,你永远不应该在 Java 中这样做吗?如果这是你的观点,我不同意。
              • @Pascal:在 Java 中没有什么能阻止您,如果您愿意,请继续。但我想,由于许多其他有用的语言不鼓励这种做法,所以在使用其他语言(例如 C++)时,你还要记住一个“规则”。如果您曾经只打算处理 Java 项目,请随意忽略我的意见。
              • 定义“举重”。我认为这就像说“不要做太多”......没有说多少太多了。
              • @jldupont,鼓励从 C++ 中的构造函数抛出,您只需正确使用 RAII 习语。此外,在编写 Java 时(因为已标记此问题),您应该编写惯用的 Java,而不必担心其他语言是如何做事的。
              • @jldupont 您的评论比您的回答更有效(这是我的观点)。但我在这里和@Glen 在一起。
              【解决方案12】:

              如果你关心构造函数中初始化的内容,我会选择“抛出”,我猜你会这样做。

              如果你隐藏了异常,那以后可能会导致问题。

              【讨论】:

              • 在构造函数中使用 throws 是正确的编码标准吗?
              • 不,不是。不要在 ctor 中打开文件。 ctor 用于内部状态的基本初始化。如果你需要做文件/网络/数据库的东西,在一个额外的 open()/init()/whatever() 方法中做。
              • @Eric,init 方法是一种代码味道。如果在每次构造对象后都必须调用 init,那么只需将 init 逻辑放在构造函数中即可。您的对象的用户不可避免地会忘记调用 init 并在他们的系统中引入错误。
              • 那又怎样?在调用 send() 之前,您需要在套接字类上调用 open()。那就是所谓的协议。如果对象未像 send() 那样初始化,则抛出异常。
              • @Eric,这是给你的另一个协议,如果文件不存在或无法打开,构造函数会抛出。很简单哈。它的优点是不需要对象的用户调用另一个方法。
              猜你喜欢
              • 2014-09-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-04-21
              • 2019-02-25
              • 2016-07-21
              • 1970-01-01
              相关资源
              最近更新 更多