Better to return None or throw an exception when fetching URL?
I have a Scala helper method that currently tries to fetch a URL and return an Option[String] with the HTML of that webpage.
If there are 开发者_如何学JAVAany exceptions (malformed url, read timeouts, etc...) or if there are any problems it returns a None. The question is, would it be better to just throw the exception so the calling code can log the exception or is it preferable to return the None in this case?
Creating exceptions is expensive because the stack trace has to be filled. Throwing and catching exceptions is also more expensive than a normal return. Considering that, you might ask yourself the following questions:
Do you want to force handling of an error by the caller? If so, don't throw an exception, as Scala has no checked-exception mechanism that forces the caller to catch them.
In case of an error, do you want to include details on why it failed? If not, you can just return
Option[A]
, whereA
is your return type, and then you'd either haveSome(validContent)
orNone
, with no additional explanation. If yes, you can return something likeEither[E, A]
or a ScalazValidation[E, A]
. All of this options force the caller to somehow unwrap the result while being free to process the errorE
as he wants. Now what shouldE
be?Do you want to provide a stack trace in case of failure? If so, you could return
Either[Exception, A]
orValidation[Exception, A]
. If you really go with the exception, you'll want to useTry[A]
, whose two possible cases areFailure(exc: Throwable)
andSuccess(value: A)
. Note that you will of course incur the costs of creating the throwable. If not, you can maybe just returnEither[String, A]
(and be extra careful to remember whetherRight
means success or failure here —Left
is usually used for errors, andRight
for the “right” value —Validation
is maybe clearer). If you want to optionally return a stack trace, you could use Lift'sBox[A]
, which could beFull(validContents)
,Empty
with no additional explanation (very similar toOption[A]
up to here), or indicate aFailure
which can store an error string and/or a throwable (and more).Do you maybe want to provide multiple indications as to why it failed? Then return
Either[Seq[String], A]
. If you do this frequently, you may probably want to use Scalaz and aValidation[NonEmptyList[String], A]
instead, which provides some other nice goodies. Look it up for more info about it or check out these usage examples.
I think that in this case, if is important to log the exceptions then by all means throw the exceptions (and possibly just return String instead of the option). Otherwise you might as well just return the None. One warning- there may be exceptions for other reasons that you don't foresee, in which case it may be dangerous to make a catch-all bit of code.
One thing that you could do is something like Lift's Box
system. A Box is essentially an Option, but with a couple features added in: A Full
is like a Some
, an Empty
is like a None
, but Lift goes a step further and has a Failure
, which is like an Empty
but with a reason/message.
The general rule of thumb is "if you can handle the exception, handle it". So there's not enough context to guess. You can use the tryFetchUrl/fetchUrl pair of methods.
精彩评论