Skip to content

Instantly share code, notes, and snippets.

@seraphy
Last active June 11, 2019 03:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seraphy/b0b667295c967bb50b64b7bd16cac166 to your computer and use it in GitHub Desktop.
Save seraphy/b0b667295c967bb50b64b7bd16cac166 to your computer and use it in GitHub Desktop.
ScalaでTry-with-resourceの実装例。https://medium.com/@dkomanov/scala-try-with-resources-735baad0fd7d の実装例のテスト。類似の仕組みについては、 このあたりにまとまっている。http://www.ne.jp/asahi/hishidama/home/tech/scala/sample/using.html#h_loan_pattern
package jp.seraphyware.example
import java.io.IOException
import org.junit.Test
import jp.seraphyware.example.ScalaTryWithResourcesExample._
/**
* テストクラス
*/
class ScalaTryWithResourceExampleTest {
/**
* クローズ時に例外を出せるテスト用リソース
*
* @param raiseError クローズ時に例外を出すか?
*/
private class TestResource(private val raiseError: Boolean) extends AutoCloseable {
println("constructor")
override def close(): Unit = {
println("close")
if (raiseError) {
println("exception when closing!")
throw new RuntimeException("TEST=EXCEPTION")
}
}
}
@Test
def testBlockNorm(): Unit = {
println("★Loan patten★")
withResources(new TestResource(false)) {
_ =>
}
}
@Test(expected = classOf[IOException])
def testBlockExcept(): Unit = {
println("★Loan patten (exception)★")
withResources(new TestResource(false)) {
_ => throw new IOException("brake!!")
}
}
@Test(expected = classOf[IOException])
def testBlockDblExcept(): Unit = {
println("★Loan patten (finally-exception)★")
withResources(new TestResource(true)) {
_ => throw new IOException("brake!!")
}
}
}
package jp.seraphyware.example
import scala.util.control.NonFatal
/**
* Java7以降のTry-With-Resource構文と同等な処理のScalaでの実装例。
* https://medium.com/@dkomanov/scala-try-with-resources-735baad0fd7d
*/
object ScalaTryWithResourcesExample {
def withResources[T <: AutoCloseable, V](r: => T)(f: T => V): V = {
val resource: T = r
require(resource != null, "resource is null")
var exception: Throwable = null
try {
f(resource)
} catch {
case NonFatal(e) =>
exception = e
throw e
} finally {
closeAndAddSuppressed(exception, resource)
}
}
private def closeAndAddSuppressed(e: Throwable, resource: AutoCloseable): Unit = {
if (e != null) {
try {
resource.close()
} catch {
case NonFatal(suppressed) =>
e.addSuppressed(suppressed)
}
} else {
resource.close()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment