Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a variable in finally block

Tags:

scala

Here is code in Scala:

def write() = {
    try {
      val out = new PrintWriter(new BufferedWriter(new FileWriter(fileName, true)))
      out.println("123")
      out.close
    } catch {
      case e: IOException => {}
    }

   //finally {
     //out.close // ops, it's not visible in this context
   //}
  }

It would be better to have "out.close" in finally block, isn't it? But I don't want to use var.

My question is, how do I achieve that?


1 Answers

A variable defined in a block is local to that block. So if you insist on using try/finally manually you will have to move the val out of the block.

However, what you are trying to achieve is to create a resource, use it in a block, and call a close method on it when leaving the block, no matter whether you leave the block normally or abnormally via an exception. This is an extremely common problem, so there is already a library for it, called Scala ARM. ARM stands for automatic resource management.

Here is the basic usage:

import resource._
for(input <- managed(new FileInputStream("test.txt")) {
  // Code that uses the input as a FileInputStream
}

There was some talk of moving this construct to the scala standard library, so in the future you probably won't even need an external dependency.

I would recommend using a library for something like this. It is just one more line in your build.sbt. But for educational purposes, here is how you would roll your own:

def managed[T <: AutoCloseable](resource:T) = new Traversable[T] {
  def foreach[U](f:T=>U) {
    try {
      f(resource)
    } finally {
      resource.close()
    }
  }
}

And here is how to use it

scala> for(reader<-managed(new java.io.FileReader("/etc/passwd"))) { println(reader.read()) }
114

scala> for(reader<-managed(new java.io.FileReader("/etc/shadow"))) { println(reader.read()) }
java.io.FileNotFoundException: /etc/shadow (Permission denied)
...

You will still get the exception, but close will be called. Of course if close throws an exception as well you this will hide the original exception. Little details like this are probably handled better in scala ARM.

like image 96
Rüdiger Klaehn Avatar answered Feb 01 '26 16:02

Rüdiger Klaehn