如果我将匿名函数作为参数传递,例如在此代码示例中:
val someMap = someData.map(line => (line.split("\\|")(0), // key
line.split("\\|")(1) + "|" + // value as string concat
line.split("\\|")(4) + "|" +
line.split("\\|")(9)))
我可以抓住,例如像这样的ArrayIndexOutOfBoundsException:
try {
val someMap = someData.map(line => (line.split("\\|")(0), // key
line.split("\\|")(1) + "|" + // value as string concat
line.split("\\|")(4) + "|" +
line.split("\\|")(9)))
} catch {
case e1: ArrayIndexOutOfBoundsException => println("exception in line " )
}
这个问题是我无法访问内部函数的作用域。在这种情况下,我想打印导致异常的line
(来自匿名函数)。
我该怎么做?有没有办法在匿名函数中捕获异常?有没有办法从外部访问匿名函数的范围以进行调试?
编辑:我正在使用Scala 2.9.3
答案 0 :(得分:3)
也许这会给你一些想法:
try {
val someMap = someData.map { line =>
try {
(line.split("\\|")(0), // key
line.split("\\|")(1) + "|" + // value as string concat
line.split("\\|")(4) + "|" +
line.split("\\|")(9)))
} catch {
case inner: ArrayIndexOutOfBoundsException => {
println("exception in " + line)
throw inner;
}
}
}
} catch {
case outer: ArrayIndexOutOfBoundsException => ...
}
答案 1 :(得分:3)
您可以使用Either
val result =
someData.map {
line =>
try {
val values = (line.split("\\|")(0), // key
line.split("\\|")(1) + "|" + // value as string concat
line.split("\\|")(4) + "|" +
line.split("\\|")(9))
Right(values)
} catch {
case e1: ArrayIndexOutOfBoundsException =>
Left(s"exception in line $line")
}
}
result.foreach {
case (Right(values)) => println(values)
case (Left(msg)) => println(msg)
}
但是如果你要从文本文件中导入数据,我会尝试这样做而没有例外(因为在这种情况下获取无效数据并不是特例):
val result =
someData.map {
line =>
val fields = line.split("\\|")
if (fields.length < 9) {
Left(s"Error in line $line")
} else {
val values = (fields(0), Seq(fields(1), fields(4), fields(9)))
Right(values)
}
}
result.foreach {
case (Right((key, values))) => println(s"$key -> ${values.mkString("|")}")
case (Left(msg)) => println(msg)
}
答案 2 :(得分:3)
其他答案使用Either
等提供了很好的功能解决方案。如果您使用的是Scala 2.10,您也可以使用Try
作为
val lines = List("abc", "ef");
println(lines.map(line => Try(line(3))));
获取List[Try[Char]]
,您可以在其中检查每个元素是否成功或失败。 (我没有尝试过这个。)
如果由于任何原因您更喜欢异常,则需要在映射函数中捕获异常并使用有关该行的信息重新抛出它。例如:
// Your own exception class holding a line that failed:
case class LineException(line: String, nested: Exception)
extends Exception(nested);
// Computes something on a line and throw a proper `LineException`
// if the processing fails:
def lineWorker[A](worker: String => A)(line: String): A =
try {
worker(line)
} catch {
case (e: Exception) => throw LineException(line, e);
}
def getNth(lines: List[String], i: Int): List[Char]
= lines.map(lineWorker(_.apply(i)));
val lines = List("abc", "ef");
println(getNth(lines, 1));
println(getNth(lines, 2));
您也可以使用Catch
中的scala.util.control.Exception
来表达它:
case class LineException(line: String, nested: Throwable)
extends Exception(nested); // we need Throwable here ^^
import scala.util.control.Exception._
// Returns a `Catch` that wraps any exception to a proper `LineException`.
def lineExceptionCatch[T](line: String): Catch[T]
= handling[T](classOf[Exception]).by(e => throw LineException(line, e));
def lineWorker[A](worker: String => A)(line: String): A =
lineExceptionCatch[A](line)(worker(line))
// ...
答案 3 :(得分:2)
首先你的外部尝试/捕获是没用的。如果列表(或其他结构)为空,map
函数将不执行任何操作=&gt;不会抛出ArrayIndexOutOfBoundsException
。
至于内循环,我会使用Scalaz Either:
来获取另一个解决方案import scalaz._
import EitherT._
import Id.Id
val someMap = someData.map { line =>
fromTryCatch[Id, (String, String)] {
(line.split("\\|")(0), // key
line.split("\\|")(1) + "|" + // value as string concat
line.split("\\|")(4) + "|" +
line.split("\\|")(9))
}
}
然后将您的操作链接到List [EitherT [...]]