提出自定义异常,返回常量或返回符号?为什么?

时间:2012-03-04 20:38:02

标签: ruby exception error-handling

假设我有一个WebCrawler课程。它可能遇到几个错误。我该如何向上传播错误?

使用例外:

class WebCrawler
  class UrlBadFormatError < StandardError; end
  class PageNotFoundError < StandardError; end
  class UnauthorizedError < StandardError; end
  def crawl(url)
    if(! url =~ /some_format/)
      raise UrlBadFormatError
    response = get(url)
    if(response.code == 404)
      raise PageNotFoundError
    if(response.code == 403)
      raise UnauthorizedError
    ... 
  end
end

或常数:

class WebCrawler
  URL_BAD_FORMAT = 1
  PAGE_NOT_FOUND = 2
  UNAUTHORZIED = 3 
  def crawl(url)
    if(! url =~ /some_format/)
      return URL_BAD_FORMAT
    response = get(url)
    if(response.code == 404)
      return PAGE_NOT_FOUND
    if(response.code == 403)
      return UNAUTHORZIED
    ... 
  end
end

或符号:

class WebCrawler
  def crawl(url)
    if(! url =~ /some_format/)
      return :url_bad_format
    response = get(url)
    if(response.code == 404)
      return :page_not_found
    if(response.code == 403)
      return :unauthorized
    ... 
  end
end

哪个最好?或者它取决于(在什么?)

5 个答案:

答案 0 :(得分:2)

对于指示程序员错误的内容,例如传递给方法的错误类型的参数,肯定会引发异常。异常将使程序崩溃,引起程序员注意他们正在错误地使用您的类的事实,因此他们可以解决问题。在这种情况下,返回错误代码是没有意义的,因为程序必须包含检查返回值的代码,但是在调试程序之后,不应该发生这样的错误。

WebCrawler课程中,预期 crawl有时会收到错误的网址作为参数吗?我认为答案可能不是。因此,当传递错误的URL时,提出异常是合适的。

当引发异常时,执行流程突然“跳转”到最里面的处理程序。当异常预期在大多数时间发生时,这可以是构造代码的有用方法,因为您可以将方法的“主流”编写为简单的直线代码而不包括关于在发生一些罕见错误情况时会发生什么的很多细节。这些细节可以与“主流”代码分开,并放入异常处理程序。但是,如果预计在正常情况下会出现错误情况,则最好将错误处理代码与“主流程”内联,以使其更清楚。如果程序的控制流程“跳转”(就像异常用于正常流控制的情况那样),这意味着读者还必须在程序文本中“跳转”,因为他们正在弄清楚它是如何工作的。

对于其他两个,我认为至少有时候,HTTP请求会返回错误代码。要确定异常或特殊返回值是否是指示此类条件的最佳方式,我会考虑 这些条件在正常使用情况下会发生的频率。还要考虑客户端代码如何以任何方式读取。如果您使用例外,则必须编写如下内容:

urls.map do |url|
  begin
    crawl(url)
  rescue PageNotFoundError
    ""
  rescue UnauthorizedError
    ""
  end
end

(顺便说一句,我认为这个代码示例显示了一些内容:如果两个自定义异常都从一个公共超类继承,那么你可以用一个rescue子句捕获它们。如果需要。)或者如果您使用错误代码,它将类似于:

urls.map do |url|
  response = crawl(url)
  if [:page_not_found, :unauthorized].include? response
    ""
  else
    response
  end
end

您认为哪种读法更好?这完全取决于你。你做想要做的一件事就是使用整数常量来表示错误。为什么要使用整数?当您在调试跟踪中打印它们时,您必须查看常量列表以查看每个常量的含义。使用符号在计算上同样有效。

答案 1 :(得分:2)

为什么不会你抛出异常?它们可以封装除了类型之外的其他信息,可以轻松获得,如果您使用的是IDE,则是一等公民。

答案 2 :(得分:0)

如果它是一个例外,那么无论如何都会引发异常!在我看来,所有这三个案例都是例外。虽然有些人可能认为4xx状态代码不是例外,因为你可能会发现它们会发生,但它们仍然是客户端错误

您还可以阅读Ruby的throw / catch,它适用于“不使用控制流异常”的情况下的异常行为(尽管我不认为这是案例)。

答案 3 :(得分:0)

你应该提出错误。如果您遇到格式错误的网址,或者找不到该网页,或者您无权访问该网页,则表示您无法继续抓取。从方法中返回引发错误或异常,并让调用者处理异常情况。

它还应包括有关错误的信息,例如错误代码,导致错误的URL以及任何其他相关信息。它可以帮助决定如何最好地处理错误,以后可以为用户格式化为有用的消息。

不应该做的事情,返回数字错误代码。 Ruby不是C.只需使用符号。

答案 4 :(得分:-1)

我反对在遇到网页上的403s,404s,格式错误的网址和类似的常见情况时使用例外。例外是指“内部”错误。在World Wild Web中,糟糕的URL完全没有例外。应该有一种方法来处理每种不同的URL疾病。我个人会将特殊值作为符号返回,或者一些“SpecialCase”对象记录发生的事情。还有未充分利用的捕获......抛出声明。