【Scala】Scala ~ 基本編 / 例外処理 ~

■ はじめに

Scala の 例外処理について扱う。
基本、Javaに近いが、Scala特有の機能もある。

なお、Option / Either については、以下の関連記事を参照のこと

Scala ~ 基本編 / Option型 ~
https://dk521123.hatenablog.com/entry/2023/03/09/000000
Scala ~ 基本編 / Either型 ~
https://dk521123.hatenablog.com/entry/2023/08/02/132315

目次

【1】try / catch / finally
【2】例外クラス定義
【3】scala.util.Try
 例1:Hello World
 例2:日付変換
 例3:日付変換 - 2

【1】try / catch / finally

* Javaと比較して、catch が若干違うだけで
 他は同じように書ける

サンプル

object  Hello {
  def main(args: Array[String]): Unit = {
    try {
      val result = 1 / 0
    } catch {
      // catch は若干違う (rethrowは同じ)
      case e: Exception => throw e
    } finally {
      // finally も Javaと同じ
      println("Done!")
    }
  }
}

【2】例外クラス定義

object DemoExceptions {
  class Demo1Exception extends RuntimeException
  class Demo2Exception extends RuntimeException
}

【3】scala.util.Try

* まずは、サンプルをみてみるのが理解が早いかも、、、

https://github.com/scala/scala/blob/2.13.x/src/library/scala/util/Try.scala

例1:Hello World

// Tryを使うには、import が必要
import scala.util.Try

object DemoExceptions {
  class DemoException extends RuntimeException
}

object Utils {
  import DemoExceptions._

  def sum(a: Int, b: Int): Int = {
    if (a < 0 || b < 0) {
      throw new DemoException
    }
    a + b
  }
}

object  Hello {
  import DemoExceptions._

  // ★注目(特に Try { ... } 部分)★
  private def demoTry(valueA: Int, valueB: Int): Try[Int] = Try {
    Utils.sum(valueA, valueB)
  }

  def main(args: Array[String]): Unit = {
    try {
      val result1 = demoTry(1, 1)
      println(result1)
      println(result1.getOrElse(-1))
      val result2 = demoTry(1, -1)
      println(result2)
      println(result2.getOrElse(-1))
    } catch {
      case e: DemoException => throw e
    } finally {
      println("Done!")
    }
  }
}

出力結果

Success(2)
2
Failure(DemoExceptions$DemoException) // 補足参照
-1
Done!

補足

catchで rethrowしている作りだが、
そもそも例外にならずに catchに来ていない

例2:日付変換

import scala.util.{Failure, Success, Try}

object Hello {
  def main(args: Array[String]): Unit = {
    val target = "2013-07-06"
    Array("yyyy/MM/dd", "yyyy-MM-dd").foreach(x => {
      val format = new java.text.SimpleDateFormat(x)
      // ★注目★
      val result = Try(format.parse(target)) match {
        case Failure(e) => Left(e)
        case Success(v) => Right(v)
      }
      println(result.getOrElse("None"))
    })
  }
}

出力結果

None
Sat Jul 06 00:00:00 JST 2013

例3:日付変換 - 2

import java.util.Date
import scala.util.Try

object Hello {
  def main(args: Array[String]): Unit = {
    val targets = Array("2013-07-06", "20130706", "2013.07.06")
    targets.zipWithIndex.foreach {
      case(target:String, index:Int) => {
        val result = getDate(target)
        // [0] Sat Jul 06 00:00:00 JST 2013
        // [1] Sat Jul 06 00:00:00 JST 2013
        // [2] None
        println(s"[${index}] ${result.getOrElse("None")}")
      }
    }
  }

  private def getDate(target: String): Option[Date] = {
    val dateFormats = Array("yyyy/MM/dd", "yyyy-MM-dd", "yyyyMMdd")
    dateFormats.foldLeft[Option[Date]](None) { (parsed, dateFormat) =>
      val format = new java.text.SimpleDateFormat(dateFormat)
      // ★注目★
      parsed.orElse(Try(format.parse(target)).toOption)
    }
  }
}

参考文献

https://qiita.com/takayahilton/items/63f00762116b6d6c7f98
https://www.baeldung.com/scala/exception-handling

関連記事

Scala ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/03/10/193805
Scala ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2023/03/12/184331
Scala ~ 基本編 / Either型 ~
https://dk521123.hatenablog.com/entry/2023/08/02/132315
Scala ~ 基本編 / Option型 ~
https://dk521123.hatenablog.com/entry/2023/03/09/000000
Scala ~ 基本編 / 日付・日時 ~
https://dk521123.hatenablog.com/entry/2023/03/08/000000