抛出额外的异常以避免代码重复

Mar*_*oDS 6 theory exception code-duplication

首先,我知道标准答案是异常永远不会用于流量控制.虽然我完全赞同这一点,但我一直在思考我有时做过的事情,我将用以下伪代码描述:

try
    string keyboardInput = read()
    int number = int.parse(keyboardInput)
    //the conversion succeeds
    if(number >= 1000) 
        //That's not what I asked for. The message to display to the user
        //is already in the catch-block below.
        throw new NumberFormatException() //well, there IS something wrong with the number...
 catch(NumberFormatException ex)  //the user entered text
    print("Please enter a valid number below 1000.")
Run Code Online (Sandbox Code Playgroud)

首先,以非常抽象的方式来看这个例子.这不一定必须发生.情况只是:

用户输入需要受到约束,并且可以通过两种方式出错,无论是通过语言定义的抛出异常,还是通过检查.用户以相同的方式报告这两个错误,因为他们不需要知道导致错误的技术差异.

我想到了几种解决方法.首先,抛出自定义异常会更好.我当时遇到的问题是,如果我在本地捕获它,如何处理另一个异常?在se中,自定义异常将导致第二个catch块,其中消息也将被复制到其中.我的解决方案

//number is wrong
throw new MyException()
catch(NumberFormatException ex) 
    throw new MyException()
catch(MyException ex) {
    print("Please enter...")
Run Code Online (Sandbox Code Playgroud)

例外名称的含义就是这里的一切.定制异常的这种应用被广泛接受,但基本上我没有做任何与第一种方式不同的东西:我被迫进入一个catch-block,尽管抛出一个自定义异常而不是标准库异常.

应用于将异常抛出到调用方法(因此没有自定义异常的catch块)的相同方式似乎更有意义.我的方法可能在技术上有两种方式出错,但实际上只有一种方式:错误的用户输入.因此,人们会写一个UserInputException并让方法抛出这个.新问题:如果这是应用程序的主要方法怎么办?

我目前没有在特定的应用程序中努力实现这种行为,我的问题纯粹是理论非语言特定的.

解决这个问题的最佳方法是什么?

Mic*_*son 5

我会认为第一个异常是低级别的,我会在调用时处理它(在这种情况下通过翻译).我发现这导致代码更容易维护和重构,因为您需要处理的异常类型较少.

try
  string keyboardInput = read()
  try
    int number = int.parse(keyboardInput)
  catch(NumberFormatException ex)
    throw MyException("Input value was not a number")

  //the conversion succeeds
  if(number >= 1000) 
    throw MyException("Input value was out of range")

catch(MyException ex)  //the user entered text
  print( ex.ToString() )
  print("Please enter a valid number below 1000.")
Run Code Online (Sandbox Code Playgroud)


Att*_*ila 1

我认为您基本上有几种方法可以在尽量减少代码重复的情况下实现此目的:

  1. 使用布尔变量/存储异常:如果您正在执行的特定任务的一般逻辑中的任何地方出现错误,您将在出现错误的第一个迹象时退出,并在单独的错误处理分支中处理该错误。

    优点:只有一个地方可以处理错误;您可以使用您喜欢的任何自定义异常/错误条件。

    缺点:您想要实现的目标的逻辑可能很难发现。

  2. 创建一个可用于通知用户错误的通用函数(预先计算/存储描述一般错误的所有信息,例如向用户显示的消息),这样当出现错误情况时,您只需调用一个函数即可发生。

    优点:对于代码的读者来说,你的意图的逻辑可能更清晰;您可以使用您喜欢的自定义异常/错误条件。

    缺点:必须在单独的位置处理错误(尽管使用预先计算/存储的值,没有太多复制粘贴,但通知用户部分很复杂)。

  3. 如果意图明确,我认为从 try 块中显式抛出异常并不是一个坏主意。如果您不想抛出系统提供的异常之一,您始终可以创建自己的异常,派生自其中之一,因此您只需要最少数量(最好是一个)的 catch 块。

    优点:只有一个地方可以处理错误情况——如果 try 块中本质上只抛出一种类型的异常。

    缺点:如果抛出不止一种类型的异常,则需要嵌套的 try-catch 块(将异常传播到最外层的异常)或非常通用的(例如异常)catch 块以避免重复错误报告。