17.4. Klauzula catch
Wyrażenie try może zawierać klauzulę catch, składającą się ze słowa kluczowego catch, po którym, w nawiasach klamrowych, znajduje się lista wyrażeń case, podobna do występującej w przypadku instrukcji match, przy czym wzorce znajdujące się w kolejnych klauzulach case powinny dopasowywać obiekt reprezentujący wyjątek, a dokładniej obiekt będący typu java.lang.Throwable lub jego podtypu. Poniższe wyrażenie try z klauzulą case nie kompiluje się, gdyż wzorzec znajdujący się w klauzuli case nie jest odpowiedniego typu.
scala> try println("hi") catch { case _: Int => }
<console>:11: error: pattern type is incompatible with expected type;
found : Int
required: Throwable
try println("hi") catch { case _: Int => }
^
Plik Try2.scala zawiera definicję metody hello, w której znajduje się wywołanie metody greet_!, zdefiniowanej w pliku Throw1.scala, opakowane wyrażeniem try z klauzulą catch. W klauzuli catch znajdują się klauzule case dopasowujące różne typy wyjątków.
Plik Try2.scala: def hello(n: Int) = try { greet_!("Hello", n) } catch { case e: IllegalArgumentException => println("Illegal argument: " + e.getMessage) "Hello."
case e: RuntimeException =>
}
Jeśli wykonywanie bloku kodu znajdującego się po słowie kluczowym
try zakończy się z powodu wygenerowania w nim wyjątku oraz jeśli ten
wyjątek może zostać dopasowany do jednego ze wzorców znajdujących się
w klauzulach case bloku catch, to kod znajdujący się po podwójnej
strzałce w pierwszej z klauzul case, która dopasowała obiekt
wyjątku, zostaje wykonany. Wynikiem całego wyrażenia try staje się
wynik wykonania tego kodu. W poniższym wywołaniu metody hello
metoda greet_! wyrzuca wyjątek typu IllegalArgumentException,
który zostaje przechwycony i obsłużony w metodzie hello. Wynikiem
metody hello staje się łańcuch znaków „Hello.” z wiersza
.
scala> :load Throw1.scala Loading Throw1.scala... greet_$bang: (greeting: String, n: Int)String scala> :load Try2.scala Loading Try2.scala... hello: (n: Int)Any
scala> hello(-1) Illegal argument: The number must be positive. res1: Any = Hello.
Po strzałce nie musi znajdować się żadne wyrażenie do wykonania. Taka
sytuacja ma miejsce w metodzie hello w wierszu
. Jeśli po strzałce
nie znajdują się żadne instrukcje, to wykonywanie wyrażenia try z
klauzulą catch kończy się. W poniższym wywołaniu metody hello
metoda greet_! wyrzuca wyjątek typu RuntimeException, który
zostaje przechwycony w metodzie hello. Wynikiem działania metody
jest wartość ().
scala> hello(0) res2: Any = ()
W bloku catch może zostać zgłoszony wyjątek. Taki wyjątek staje się wynikiem całego wyrażenia try. Taka sytuacja ma miejsce w poniższym przykładzie.
scala> try throw new Exception("1") catch {
| case ex: Exception =>
| println("ex: "+ex)
| throw new Exception("2")
| }
ex: java.lang.Exception: 1
java.lang.Exception: 2
at .liftedTree1$1(<console>:14)
... 41 elided
Kolejny przykład pokazuje sytuację, w której przechwycony wyjątek jest ponownie wyrzucany w bloku catch.
scala> try throw new Exception("1") catch {
| case ex: Exception =>
| println("ex: "+ex)
| throw ex
| }
ex: java.lang.Exception: 1
java.lang.Exception: 1
at .liftedTree1$1(<console>:11)
... 41 elided
Jeśli wykonanie bloku kodu znajdującego się po słowie kluczowym try zakończy się z powodu wygenerowania wyjątku, ale jeśli wygenerowany obiekt wyjątku nie zostanie dopasowany do żadnego z wzorców w klauzulach case, to wykonywanie całego wyrażenia try kończy się wyrzuceniem tego wyjątku. W poniższym wywołaniu metody hello metoda greet_! wyrzuca wyjątek typu Exception, który nie zostaje przechwycony.
scala> hello(8) java.lang.Exception: Number too big: 8 at .greet_$bang(<console>:13) at .hello(<console>:13) ... 33 elided
Jeśli wykonanie wyrażenia znajdującego się po słowie kluczowym try zakończy się bez generowania wyjątku, to jego wynik staje się wynikiem całego wyrażenia try. W poniższym wywołaniu metody hello metoda greet_! nie wyrzuca wyjątku, a wynik tej metody staje się wynikiem wywołania metody hello.
scala> hello(4) res6: Any = Hello!!!!
Plik Try2.scala:
def hello(n: Int) =
try {
greet_!("Hello", n)
} catch {
case e: IllegalArgumentException =>
println("Illegal argument: " + e.getMessage)
"Hello." 