17.8. Zamiana wyjątków na wartości

Wyjątki można przechwytywać i zamieniać na obiekty typu Option lub Either. Obiekt Exception z pakietu scala.util.control umożliwia przechwytywanie wyjątków i zamianę ich na wartości. Metody div1 i div2 z pliku ToValues1.scala ilustrują dwa spośród możliwych sposobów jego użycia.

Plik ToValues1.scala:
import scala.util.control.Exception._
def div1(a: Int, b: Int) = catching(classOf[ArithmeticException]) opt a/b
def div2(a: Int, b: Int) = catching(classOf[ArithmeticException]) either a/b

Obie metody wykonują dzielenie wartości parametrów a i b przechwytując mogący się pojawić wyjątek ArithmeticException. Metoda div1 zwraca wartość typu Option[Int], a metoda div2 wartość typu Either[Throwable,Int]. W przypadku poprawnego wykonania dzielenia metoda div1 zwraca wynik opakowany w instancję klasy Some, a metoda div2 wynik opakowany w instancję klasy Right. W przypadku wystąpienia wyjątku ArithmeticException pierwsza z metod zwraca obiekt None, a druga zwraca obiekt wyjątku opakowany w instancję klasy Left.

scala> :load ToValues1.scala
Loading ToValues1.scala...
import scala.util.control.Exception._
div1: (a: Int, b: Int)Option[Int]
div2: (a: Int, b: Int)scala.util.Either[Throwable,Int]

scala> div1(1,0)
res0: Option[Int] = None

scala> div1(4,2)
res1: Option[Int] = Some(2)

scala> div2(1,0)
res2: scala.util.Either[Throwable,Int] = Left(java.lang.ArithmeticException: / by zero)

scala> div2(4,2)
res3: scala.util.Either[Throwable,Int] = Right(2)

Metoda safe z pliku ToValues1.scala pokazuje inny przykład, w którym przechwytywane są dwa rodzaje wyjątków: ArithmeticException i NumberFormatException, a metoda zwraca wartość typu Either[Throwable,Int].

Plik ToValues2.scala:
import scala.util.control.Exception._
def safe(c: => Int) = (catching(classOf[ArithmeticException]) or
                       catching(classOf[NumberFormatException])).
                       andFinally{ println("finally safe") }.either(c)

Dodatkowo, niezależnie od przebiegu obliczeń wartości c — zarówno w przypadku wystąpienia wyjątku jak i w przypadku jego braku — wykonywany jest kod przekazany metodzie andFinally.

scala> :load ToValues2.scala
Loading ToValues2.scala...
import scala.util.control.Exception._
safe: (c: => Int)scala.util.Either[Throwable,Int]

scala> safe{4/2}
finally safe
res4: scala.util.Either[Throwable,Int] = Right(2)

scala> safe{1/0}
finally safe
res5: scala.util.Either[Throwable,Int] = Left(java.lang.ArithmeticException: / by zero)

scala> safe{"a".toInt}
finally safe
res6: scala.util.Either[Throwable,Int] = Left(java.lang.NumberFormatException: For input string: "a")

Obiekt Try z pakietu scala.util również pozwala na zamianę wyjątków na wartości. Wyrażenie przekazane metodzie apply tego obiektu jest ewaluowane i jeśli w wyniku tej ewaluacji zostanie wygenerowany wyjątek, to ten wyjątek zostanie przez metodę apply zwrócony, opakowany w instancję klasy Failure. W przeciwnym wypadku metoda apply zwróci wynik ewaluacji wyrażenia opakowany w instancję klasy Success. Failure oraz Success są podklasami klasy Try.

Plik ToValues3.scala:
import scala.util.Try
def div3(a: Int, b: Int) = Try( a/b )

Plik ToValues3.scala zawiera przykład użycia obiektu Try.

scala> :load ToValues3.scala
Loading ToValues3.scala...
import scala.util.Try
div3: (a: Int, b: Int)scala.util.Try[Int]

scala> div3(4,2)
res7: scala.util.Try[Int] = Success(2)

scala> div3(1,0)
res8: scala.util.Try[Int] = Failure(java.lang.ArithmeticException: / by zero)

Język programowania Scala Wydanie 2. Copyright © Grzegorz Balcerek 2016

Licencja Creative Commons

Ten utwór jest dostępny na licencji Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowe.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.