在Scala中处理和抛出异常

问题描述 投票:3回答:3

我有以下实现:

  val dateFormats = Seq("dd/MM/yyyy", "dd.MM.yyyy")
  implicit def dateTimeCSVConverter: CsvFieldReader[DateTime] = (s: String) => Try {
    val elem = dateFormats.map {
      format =>
        try {
          Some(DateTimeFormat.forPattern(format).parseDateTime(s))
        } catch {
          case _: IllegalArgumentException =>
            None
        }
    }.collectFirst {
      case e if e.isDefined => e.get
    }
    if (elem.isDefined)
      elem.get
    else
      throw new IllegalArgumentException(s"Unable to parse DateTime $s")
  }

基本上我正在做的是,我正在运行我的Seq并试图用不同的格式解析DateTime。然后我收集第一个成功的,如果不是,我将异常抛回。

我对代码并不完全满意。有没有更好的方法让它更简单?我需要传递给调用者的异常消息。

scala
3个回答
5
投票

您的代码的一个问题是无论日期是否已经解析,它都会尝试所有模式。您可以使用延迟集合,如Stream来解决此问题:

 def dateTimeCSVConverter(s: String) = Stream("dd/MM/yyyy", "dd.MM.yyyy")
       .map(f => Try(DateTimeFormat.forPattern(format).parseDateTime(s))
       .dropWhile(_.isFailure)
       .headOption

更好的是jwvh使用find提出的解决方案(你不必调用headOption):

 def dateTimeCSVConverter(s: String) = Stream("dd/MM/yyyy", "dd.MM.yyyy")
       .map(f => Try(DateTimeFormat.forPattern(format).parseDateTime(s))
       .find(_.isSuccess)

如果没有匹配的模式,它返回None。如果你想在这种情况下抛出异常,你可以用getOrElse解开选项:

 ...
 .dropWhile(_.isFailure)
 .headOption
 .getOrElse(throw new IllegalArgumentException(s"Unable to parse DateTime $s"))

重要的是,当任何验证成功时,它将不会更进一步,但会立即返回解析日期。


8
投票

这是一种可能的解决方案,可以遍历所有选项

  val dateFormats = Seq("dd/MM/yyyy", "dd.MM.yyyy")
  val dates = Vector("01/01/2019", "01.01.2019", "01-01-2019")
    dates.foreach(s => {
      val d: Option[Try[DateTime]] = dateFormats
        .map(format => Try(DateTimeFormat.forPattern(format).parseDateTime(s)))
        .filter(_.isSuccess)
        .headOption
      d match {
        case Some(d) => println(d.toString)
        case _ => throw new IllegalArgumentException("foo")
      }
    })

这是一种替代解决方案,可返回第一次成功转换(如果有)

  val dateFormats = Seq("dd/MM/yyyy", "dd.MM.yyyy")
  val dates = Vector("01/01/2019", "01.01.2019", "01-01-2019")
  dates.foreach(s => {
    dateFormats.find(format => Try(DateTimeFormat.forPattern(format).parseDateTime(s)).isSuccess) match {
      case Some(format) => println(DateTimeFormat.forPattern(format).parseDateTime(s))
      case _ => throw new IllegalArgumentException("foo")
    }
  })

3
投票

我现在好像这样甜蜜!我更喜欢这个!如果您想收集所有成功和所有失败,请使用此选项。请注意,当您需要在找到一个成功后立即退出循环时,这可能有点无效!

implicit def dateTimeCSVConverter: CsvFieldReader[DateTime] = (s: String) => Try {
    val (successes, failures) = dateFormats.map {
      case format => Try(DateTimeFormat.forPattern(format).parseDateTime(s))
    }.partition(_.isSuccess)
    if (successes.nonEmpty)
      successes.head.get
    else
      failures.head.get
  }
© www.soinside.com 2019 - 2024. All rights reserved.