代码之家  ›  专栏  ›  技术社区  ›  Alexander Arendar

来源问题。在finally block中尝试关闭时来自URL

  •  1
  • Alexander Arendar  · 技术社区  · 7 年前

    以下代码段工作正常:

    def using[A, B <: {def close(): Unit}] (closeable: B) (f: B => A): A =
      try { f(closeable) } finally { closeable.close() }
    
    def loadDictionaryFromNet():List[String] =
      using(Source.fromURL("http://www.mieliestronk.com/corncob_caps.txt", "UTF-8"))(_.getLines().toList)
    
      val dictionary = loadDictionaryFromNet() filter(_.forall(_.isLetter))
    

    但是当我尝试将类型更改为 Seq[String] 如下所示:

    def using[A, B <: {def close(): Unit}] (closeable: B) (f: B => A): A =
      try { f(closeable) } finally { closeable.close() }
    
    def loadDictionaryFromNet():Seq[String] =
      using(Source.fromURL("http://www.mieliestronk.com/corncob_caps.txt", "UTF-8"))(_.getLines().toSeq)
    
      val dictionary = loadDictionaryFromNet() filter(_.forall(_.isLetter))
    

    然后抛出以下异常:

    Exception in thread "main" java.io.IOException: stream is closed
        at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.ensureOpen(HttpURLConnection.java:3348)
        at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3373)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
        at java.io.InputStreamReader.read(InputStreamReader.java:184)
        at java.io.BufferedReader.fill(BufferedReader.java:161)
        at java.io.BufferedReader.readLine(BufferedReader.java:324)
        at java.io.BufferedReader.readLine(BufferedReader.java:389)
        ... 
    

    当我将类型更改为 IndexedSeq 它又起作用了。

    “感觉”就像 toSeq 事实上,产生了一些部分延迟流,这些流没有立即完全消耗,但有一些延迟。

    你能解释一下引擎盖下发生了什么吗?

    1 回复  |  直到 7 年前
        1
  •  1
  •   tkachuko    7 年前

    事实上,你是对的。让我们从 Source.fromURL

    1. 来源来自URL => scala.io.BufferedSource
    2. BufferedSource.getLines => BufferedLineIterator
    3. BufferedLineIterator.toSeq 从调用 scala.collection.TraversableOnce
    4. TraversableOnce 实现方法 toSeq 作为: def toSeq: Seq[A] = toStream
    5. toStream 是从课堂上取下来的 Iterator .

    实施如下:

    def toStream: Stream[A] =
      if (self.hasNext) Stream.cons(self.next(), self.toStream)
      else Stream.empty[A]
    

    哎呀,真是一段旅程。是的,您最终构建了一个懒惰的流,因此您得到了您在问题中提到的异常。