Stackoverflow when use bufferedInputStream as a tr

2019-06-24 05:21发布

问题:

I am trying to solve a problem given by the Book "Scala for the Impatient", which asked to implement java's BufferedInputStream as a trait. Here is my implementation,

trait Buffering {           
    this:InputStream =>
        private[this] val bis = {
            new JavaBufferedInputStream(this)
        }
        override def read = bis.read
        override def read(byte:Array[Byte], off:Int, len:Int) = bis.read(byte, off, len)
        override def available = bis.available
        override def close() {
            bis.close
        }
        override def skip(n:Long) = bis.skip(n)
}

def main(args:Array[String]) {
    val bfis = new FileInputStream(new File("foo.txt")) with Buffering
    println(bfis.read)
    bfis.close
}

But this give me a java stackoverflow error, so what's wrong with it? Thanks!

回答1:

It looks like you are getting a stack overflow where you don't expect one. The key to troubleshoot these is to look at the repeating cycle of the stack trace. It usually points to what is repeatedly allocating frames. Here it will show something like that:

at C.Buffering$class.read(C.scala:12)
at C.C$$anon$1.read(C.scala:23)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at C.Buffering$class.read(C.scala:12)
at C.C$$anon$1.read(C.scala:23)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at C.Buffering$class.read(C.scala:12)

So reading from bottom to top, it looks like your read(byte, ...) is calling bis.read(byte, ...) which is calling BufferedInputStream.read which is then calling your read(byte, ...) again.

It would appear that new BufferedInputStream(this) is calling read on the underlying InputStream but since the underlying this is your object that then delegates calls on bis we have infinite recursion.

I'm guessing that the author wants you to use the abstract override stackable modifications pattern where you can use super to refer to the right read method.



回答2:

Maybe this is the answer. Just maybe from what i understood.

trait Buffering extends InputStream{
abstract override def read()=
{
    println("Hello");
    super.read()
}
}
val t = new ByteArrayInputStream("hello".getBytes()) with Buffering


回答3:

I have been going through "Scala for the Impatient". Here is what I have as a solution to exercise 8 in chapter 10:

import java.io._

object BufferedInputStream extends App {

  trait Buffering {
    this: FileInputStream =>
    val br = new BufferedInputStream(this)
  }

  def bufferedReader(f: String): Unit = {
    val fis = new FileInputStream(f) with Buffering
    var c = 0
    var blen = 8192
    var len = 0
    var b = new Array[Byte](blen)
    while (fis.br.available > 0) {
      if (fis.br.available > blen) len = blen
      else len = fis.br.available
      c = fis.br.read(b, 0, len)
      if (c == -1) return
      print((for (i <- 0 to (c - 1)) yield b(i).toChar).mkString)
    }
    fis.br.close
    fis.close
  }

  bufferedReader("webpagexample")

}


标签: scala traits