Scala Language
Obsługa błędów
Szukaj…
Próbować
Używanie Wypróbuj z map
, getOrElse
i flatMap
:
import scala.util.Try
val i = Try("123".toInt) // Success(123)
i.map(_ + 1).getOrElse(321) // 124
val j = Try("abc".toInt) // Failure(java.lang.NumberFormatException)
j.map(_ + 1).getOrElse(321) // 321
Try("123".toInt) flatMap { i =>
Try("234".toInt)
.map(_ + i)
} // Success(357)
Używanie Try
z dopasowaniem wzoru:
Try(parsePerson("John Doe")) match {
case Success(person) => println(person.surname)
case Failure(ex) => // Handle error ...
}
Zarówno
Różne typy danych dla błędu / sukcesu
def getPersonFromWebService(url: String): Either[String, Person] = {
val response = webServiceClient.get(url)
response.webService.status match {
case 200 => {
val person = parsePerson(response)
if(!isValid(person)) Left("Validation failed")
else Right(person)
}
case _ => Left(s"Request failed with error code $response.status")
}
}
Dopasowywanie wzorca dla dowolnej wartości
getPersonFromWebService("http://some-webservice.com/person") match {
case Left(errorMessage) => println(errorMessage)
case Right(person) => println(person.surname)
}
Konwertuj dowolną wartość na opcję
val maybePerson: Option[Person] = getPersonFromWebService("http://some-webservice.com/person").right.toOption
Opcja
Używanie wartości null
jest zdecydowanie odradzane, chyba że interakcja ze starszym kodem Java, który oczekuje null
. Zamiast Option
powinna być stosowana, gdy wynik funkcji może być albo coś ( Some
) albo nic ( None
).
Blok try-catch jest bardziej odpowiedni do obsługi błędów, ale jeśli funkcja może nic nie zwracać, Option
jest odpowiednia i prosta.
Option[T]
może być Some(value)
(zawiera wartość typu T
) lub None
:
def findPerson(name: String): Option[Person]
Jeśli nie zostanie znaleziona żadna osoba, None
można zwrócić. W przeciwnym razie zwracany jest obiekt typu Some
zawierający obiekt Person
. Poniżej przedstawiono sposoby obsługi obiektu typu Option
.
Dopasowywanie wzorów
findPerson(personName) match {
case Some(person) => println(person.surname)
case None => println(s"No person found with name $personName")
}
Korzystanie z mapy i getOrElse
val name = findPerson(personName).map(_.firstName).getOrElse("Unknown")
println(name) // Prints either the name of the found person or "Unknown"
Używanie krotnie
val name = findPerson(personName).fold("Unknown")(_.firstName)
// equivalent to the map getOrElse example above.
Konwertowanie na Javę
Jeśli chcesz przekonwertować typ Option
na zerowy typ Java dla interoperacyjności:
val s: Option[String] = Option("hello") s.orNull // "hello": String s.getOrElse(null) // "hello": String val n: Option[Int] = Option(42) n.orNull // compilation failure (Cannot prove that Null <:< Int.) n.getOrElse(null) // 42
Obsługa błędów pochodzących z kontraktów futures
Kiedy exception
zostanie zgłoszony w Future
, możesz (powinieneś) użyć recover
aby go obsłużyć.
Na przykład,
def runFuture: Future = Future { throw new FairlyStupidException }
val itWillBeAwesome: Future = runFuture
... rzuci Exception
z Future
. Ale widząc, jak możemy przewidzieć, że Exception
typu FairlyStupidException
z dużym prawdopodobieństwem, możemy konkretnie obsłużyć tę sprawę w elegancki sposób:
val itWillBeAwesomeOrIllRecover = runFuture recover {
case stupid: FairlyStupidException =>
BadRequest("Another stupid exception!")
}
Jak widać metoda podana w celu recover
to PartialFunction
nad domeną wszystkich Throwable
, więc możesz obsłużyć tylko kilka typów, a następnie pozwolić reszcie przejść do eteru obsługi wyjątków na wyższych poziomach w stosie Future
.
Zauważ, że jest to podobne do uruchamiania następującego kodu w kontekście innym niż Future
:
def runNotFuture: Unit = throw new FairlyStupidException
try {
runNotFuture
} catch {
case e: FairlyStupidException => BadRequest("Another stupid exception!")
}
Naprawdę ważne jest zajmowanie się wyjątkami generowanymi w Future
s, ponieważ przez większość czasu są bardziej podstępni. Zwykle nie dostają wszystkiego w twarz, ponieważ działają w innym kontekście wykonywania i wątku, a zatem nie monitują o ich naprawę, gdy się zdarzają, szczególnie jeśli nie zauważysz niczego w dziennikach lub zachowaniu podanie.
Korzystanie z klauzul try-catch
Oprócz funkcjonalnych konstrukcji, takich jak Try
, Option
i Either
do obsługi błędów, Scala obsługuje również składnię podobną do Javy, używając klauzuli try-catch (z potencjalnym blokiem w końcu). Klauzula catch jest dopasowaniem wzorca:
try {
// ... might throw exception
} catch {
case ioe: IOException => ... // more specific cases first
case e: Exception => ...
// uncaught types will be thrown
} finally {
// ...
}
Konwertuj wyjątki na jeden lub na typ opcji
Aby przekonwertować wyjątki na typy Either
lub Option
, można użyć metod podanych w scala.util.control.Exception
import scala.util.control.Exception._
val plain = "71a"
val optionInt: Option[Int] = catching(classOf[java.lang.NumberFormatException]) opt { plain.toInt }
val eitherInt = Either[Throwable, Int] = catching(classOf[java.lang.NumberFormatException]) either { plain.toInt }