在Scala中处理和引发异常

spa*_*rkr 4 scala

我有以下实现:

  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")
  }
Run Code Online (Sandbox Code Playgroud)

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

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

Krz*_*sik 5

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

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

更好的是jwvh与find提出的解决方案(您不必致电headOption):

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

None如果没有模式匹配则返回。如果您想在这种情况下引发异常,则可以使用以下命令uwrap选项getOrElse

 ...
 .dropWhile(_.isFailure)
 .headOption
 .getOrElse(throw new IllegalArgumentException(s"Unable to parse DateTime $s"))
Run Code Online (Sandbox Code Playgroud)

重要的是,当任何验证成功时,它不会继续进行,而是立即返回解析的日期。

  • 或`.find(_。isSuccess).getOrElse(...)` (4认同)

w4b*_*4bo 5

这是一个可能会遍历所有选项的解决方案

  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")
      }
    })
Run Code Online (Sandbox Code Playgroud)

这是一种替代解决方案,如果有的话,它会返回首次成功的转换

  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")
    }
  })
Run Code Online (Sandbox Code Playgroud)