我有以下scala代码,它接受一个字符串,与UTF-8字符混淆,然后尝试通过Source.fromInputStream读取它:
import java.io.ByteArrayInputStream
import java.nio.charset.StandardCharsets.UTF_8
import scala.io.Source
val stringSourceAsBytes = "hellö wörld".getBytes(UTF_8)
val messedUpUTF8 = 128.toByte +: stringSourceAsBytes
val linesIterator : Iterator[String] =
try {
val input = new ByteArrayInputStream(messedUpUTF8)
Source.fromInputStream(input).getLines()
}catch{
case exc: Throwable => println(" This is an exception !")
Iterator()
}
linesIterator.mkString("\n")
我不应该看到"这是一个例外!"信息 ?因为我没有看到它。 事实上,我得到了一个印刷的堆栈跟踪,但我无法捕捉异常并正确处理它......
BTW:我的控制台显示:
java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(IO.sc:277)
at sun.nio.cs.StreamDecoder.implRead(IO.sc:335)
at sun.nio.cs.StreamDecoder.read(IO.sc:174)
at java.io.InputStreamReader.read(IO.sc:181)
at java.io.BufferedReader.fill(IO.sc:157)
at java.io.BufferedReader.readLine(IO.sc:322)
at java.io.BufferedReader.readLine(IO.sc:388)
at scala.io.BufferedSource$BufferedLineIterator.hasNext(IO.sc:66)
at scala.collection.Iterator.toString(IO.sc:1409)
at scala.collection.Iterator.toString$(IO.sc:1409)
at scala.collection.AbstractIterator.toString(IO.sc:1413)
at #worksheet#.#worksheet#(IO.sc:53)
答案 0 :(得分:1)
这里有两件有趣的事情发生在这里:
try-catch
- 块您没有看到"This is an exception !"
- 消息,因为实例化延迟迭代器不会尝试从流中读取单个字节。这个try-catch
块成功并愉快地返回滴答作响的定时炸弹,实际错误发生在try-catch
之外。
但是,如果强制迭代器获取所有字节,例如通过附加.mkString
:
import java.io.ByteArrayInputStream
import java.nio.charset.StandardCharsets.UTF_8
import scala.io.Source
val stringSourceAsBytes = "hellö wörld".getBytes(UTF_8)
val messedUpUTF8 = 128.toByte +: stringSourceAsBytes
val streamContent =
try {
val input = new ByteArrayInputStream(messedUpUTF8)
Source.fromInputStream(input).getLines().mkString("\n")
}catch{
case exc: Throwable => println(" This is an exception !")
}
然后你得到输出:
This is an exception !
正如所料。您的堆栈跟踪似乎来自其他地方,请再次检查确切的行号。
问题编辑后更新
要在更新的代码中查看" This is an exception !"
消息,您必须捕获抛出异常的位置,而不是定义惰性迭代器的位置:
import java.io.ByteArrayInputStream
import java.nio.charset.StandardCharsets.UTF_8
import scala.io.Source
val stringSourceAsBytes = "hellö wörld".getBytes(UTF_8)
val messedUpUTF8 = 128.toByte +: stringSourceAsBytes
// building the exception-bomb is harmless
val linesIterator: Iterator[String] = {
val input = new ByteArrayInputStream(messedUpUTF8)
Source.fromInputStream(input).getLines()
}
val combinedLines: String = try {
// detonating the exception-bomb should be surrounded by try-catch
linesIterator.mkString("\n")
} catch {
case exc: Throwable => {
println(" This is an exception !")
""
}
}
再次打印This is an exception !
并将combinedLines
设置为空字符串。
EDIT-2:REPL
如果由于某种原因坚持在repl中运行它,那么你就不能让“中毒”迭代器逃到范围内,因为Repl因某些原因无法处理它,并且自我吹嘘。
这在repl中有效,但这与第一个解决方案基本相同:
import java.io.ByteArrayInputStream
import java.nio.charset.StandardCharsets.UTF_8
import scala.io.Source
val stringSourceAsBytes = "hellö wörld".getBytes(UTF_8)
val messedUpUTF8 = 128.toByte +: stringSourceAsBytes
val combinedLines: String = try {
val linesIterator: Iterator[String] = {
val input = new ByteArrayInputStream(messedUpUTF8)
Source.fromInputStream(input).getLines()
}
linesIterator.mkString("\n")
} catch {
case exc: Throwable => {
println(" This is an exception !")
""
}
}
REPL无法处理即将抛出异常的迭代器。原因是它在迭代器上调用hasNext
(它为有效迭代器打印non-empty iterator
描述,因此它必须调用hasNext
一次)。但是,当您调用hasNext
时,您的流会抛出异常,如下面的代码段所示:
scala> val it = try {
Source.fromInputStream(
new ByteArrayInputStream(messedUpUTF8)).getLines().hasNext
} catch { case t: Throwable =>
println("yes, hasNext blows up the REPL")
}
结果:
yes, hasNext blows up the REPL
以脚本运行(或者尝试粘贴模式),然后按预期工作。