2

即使应用程序需要大量异常,定义和抛出自定义异常是否是一种好习惯?

  • EntityNotFoundException
  • EntityAlreadyExistsException
  • EntityNotUniqueException
  • EntityNotAddedException
  • EntityNotUpdatedException
  • EntityNotDeletedException
  • QuizOverException
  • 测验过期异常
  • TableAlreadyBookedException
  • EndDateMustBeGreaterThanStartDateException

我试图命名这些示例异常名称以尽可能好地描述它们的目的。我希望他们能对我要问的问题有所了解。

不要只用这些例外来限制您的想象力,而是在您的应用程序生命周期中可能出现的所有情况。考虑 CRUD 和业务异常。

我知道抛出和捕获异常在性能方面是一个昂贵的过程,但它们不是提供了一种更优雅的方式来开发你的应用程序吗?

  • EntityNotFoundException抛出 a而不是编写 if 语句来检查实体是否为空不是更好吗?
  • EntityAlreadyExistsException抛出 a而不是编写额外的 if 语句会调用一个方法来检查具有给定 Id 的实体是否已经存在,这不是更好吗?
  • EntityNotAddedException抛出 a而不是检查指定事务是否成功的 bool 类型的返回值不是更好吗?如果我们想返回一个对象怎么办?

我觉得答案会是“你不应该使用EntityNotFoundException而是检查是否为空,但你应该使用EntityAlreadyExistsException”,“没有圣杯”。

我想知道这样做的优雅方式是什么?

4

4 回答 4

5

请记住,例外应该代表特殊情况,您的所有问题只能真正得到回答——这取决于

您打算在何时何地抛出特定异常的上下文自然会决定它是否有意义。例如,如果您尝试检索应该存在但不存在的实体,那么抛出 anEntityNotFoundException将被认为是合适的,因为我们现在有一个例外情况。另一方面,如果您在创建新实体之前检查实体是否已经存在,那么您可能会争辩说,因为我们知道实体可能存在也可能不存在,所以这并不是真正的例外情况。

就像我说的那样,是否应该抛出异常实际上取决于情况的上下文和应用程序的性质,但是,您最终不想做的一件事是使用异常控制程序流。

为了帮助区分何时适合使用异常与业务逻辑,只需问自己“这种特殊情况是否有效? ”或者换句话说“应用程序可以发现自己处于这种状态吗? ”。如果答案是肯定的,请使用逻辑来控制应用程序的流程并处理这种情况,否则您想抛出一个Exception有效地中断程序流程并通知用户某些事情不太正确的事情。

于 2013-07-31T12:22:35.330 回答
2

C++ 中异常处理范例的一个主要限制是,它被 Java 和随后的 .NET 继承,如果调用Foothrows a BozException,它可能有两种截然不同的含义:

  • 在执行期间检测到一些条件,Foo这意味着它应该抛出一个BozException.

  • Foo 调用了一些它不希望抛出的BozException方法,但是该方法仍然抛出了一个并且Foo没有捕获它,异常被抛出了Foo

尽管框架指南不鼓励在现有异常似乎“适合”时使用自定义异常,但缺乏任何标准方法让代码捕获框架定义的异常以了解它是否真的代表预期的情况是一个相当大的问题使用框架异常(如InvalidOperationException)来报告调用者可能想要处理的业务逻辑情况(例如尝试添加到Dictionary具有相同 ID 的记录)的缺点。如果您可以容忍与定义异常相关的样板,我建议最好在太多而不是太少方面犯错(尽管您可能希望对可能以相同方式处理的异常使用继承)。

于 2013-08-27T17:00:49.357 回答
2

在创建例外时询问它们的附加值。有人会关心要捕获的特定类型的异常吗?异常会有不同的字段来帮助异常处理吗?带有自定义消息的更抽象的异常可以节省您编写没有价值的异常的时间。

使用异常来控制程序流被认为是个坏主意。以下是一些原因:

  • 为错误处理的概念创建了异常
  • 你说的性能
  • 你可能会忘记处理一些异常
  • 如果您使用检查的异常,您可能需要为您不关心或不知道如何处理的异常编写处理程序。
  • 异常会增加程序中的不确定性(异常处理时抛出的异常、finally 语句......)

还有其他解决条件语句的方法,看看 scala 编程语言及其对“monads”的使用。

于 2013-07-31T12:00:52.657 回答
1

与软件开发中的几乎所有事情一样,给定一般规则或最佳实践,技能就是知道何时以及如何应用它。

我应该编程到接口吗?是的!我是否应该让我编写的每一个类都实现一个相应的接口,并且只对该抽象进行编程?我可以做到,但编写一个非常简单的应用程序会花费我很长时间,而且我的工作效率会停滞不前。

单一职责 - 这是一件好事吗?是的!我写的每一节课都只有一个职责吗?不——部分是因为我自己作为程序员的失败,但也因为我最终会得到过多的单方法类和无法管理的断开连接的代码库。

现在让我们转向错误处理:

首先,通过查看您对James 的回答的评论,让我们澄清一下,使用错误代码异常处理代表了您的应用程序中处理错误的两种不同模型,并且作为一般规则,它们不应混用。

让我们假设您正在使用异常处理并提出以下论点:

为什么我们会抛出异常?

我们抛出异常是因为发生了一些不好的事情。如果我们期望某个场景发生在某个时间点,那么它就在我们的应用程序的流程中,因此并不例外——因此抛出 anException是不合适的!

有了这个论点,抛出除了顶级Exception类之外的任何东西都没有什么意义,因为任何其他异常都意味着我们已经预见到这种情况并且已经能够将额外的元数据附加到异常中。

为什么要处理异常?

抛出异常后,我们希望有人能在某个地方处理它,希望能够将应用程序恢复到一致的状态。但是,如果异常确实是异常的——我们无法知道什么状态已被破坏,因此异常处理是徒劳的。

这不是太过分了吗?

嗯 - 这正是错误处理在面向服务的架构中的工作方式。一个健壮的服务不应该透露发生异常时所发生的任何有罪的细节(这是一个安全漏洞,并在服务和客户端之间引入了耦合)——所有客户端需要知道的是发生了一些不好的事情

然而,我猜我们是在一个面向对象的环境中工作的,在这个环境中,我们准备好接受一个实现和它的消费者之间更高程度的耦合。正是这一点很重要——通过引入一个异常层次结构,它公开了有关异常的详细信息,您增加了应用程序中的耦合(消费者需要详细了解您可能抛出的所有异常)。

在软件中,我们努力实现松散耦合的代码库,使其易于维护和扩展。毫无疑问,在 SOA 异常处理方法和您在问题中描述的方法之间存在一种快乐的媒介——发现最佳点是开发人员的技能。

于 2013-08-29T13:08:20.937 回答