Scala Language
Gestione degli errori
Ricerca…
Provare
Usando Prova con map
, getOrElse
e 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)
Uso di Try
con corrispondenza del modello:
Try(parsePerson("John Doe")) match {
case Success(person) => println(person.surname)
case Failure(ex) => // Handle error ...
}
O
Diversi tipi di dati per errore / successo
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")
}
}
Pattern matching su entrambi i valori
getPersonFromWebService("http://some-webservice.com/person") match {
case Left(errorMessage) => println(errorMessage)
case Right(person) => println(person.surname)
}
Converti un valore in Opzione
val maybePerson: Option[Person] = getPersonFromWebService("http://some-webservice.com/person").right.toOption
Opzione
L'uso di valori null
è fortemente sconsigliato, a meno che non si interagisca con il codice Java legacy che si aspetta null
. Invece, Option
dovrebbe essere usato quando il risultato di una funzione potrebbe essere qualcosa ( Some
) o nothing ( None
).
Un blocco try-catch è più appropriato per la gestione degli errori, ma se la funzione potrebbe legittimamente non restituire nulla, Option
è appropriato da usare e semplice.
Option[T]
può essere Some(value)
(contiene un valore di tipo T
) o None
:
def findPerson(name: String): Option[Person]
Se nessuna persona viene trovata, None
può essere restituita. Altrimenti, viene restituito un oggetto di tipo Some
contenente un oggetto Person
. Quello che segue sono i modi per gestire un oggetto di tipo Option
.
Pattern Matching
findPerson(personName) match {
case Some(person) => println(person.surname)
case None => println(s"No person found with name $personName")
}
Utilizzando la mappa e getOrElse
val name = findPerson(personName).map(_.firstName).getOrElse("Unknown")
println(name) // Prints either the name of the found person or "Unknown"
Usando la piega
val name = findPerson(personName).fold("Unknown")(_.firstName)
// equivalent to the map getOrElse example above.
Conversione in Java
Se è necessario convertire un tipo di Option
in un tipo Java null-enabled per l'interoperabilità:
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
Gestione degli errori originati nei futures
Quando exception
viene lanciata dall'interno di un Future
, puoi (dovresti) utilizzare recover
per gestirlo.
Per esempio,
def runFuture: Future = Future { throw new FairlyStupidException }
val itWillBeAwesome: Future = runFuture
... genererà Exception
dall'interno del Future
. Ma visto che siamo in grado di prevedere che un Exception
di tipo FairlyStupidException
con una probabilità alta, siamo in grado di gestire questo specifico caso in modo elegante:
val itWillBeAwesomeOrIllRecover = runFuture recover {
case stupid: FairlyStupidException =>
BadRequest("Another stupid exception!")
}
Come puoi vedere il metodo dato per recover
è una PartialFunction
sul dominio di tutti i Throwable
, quindi puoi gestire solo alcuni tipi e lasciare che il resto entri nell'etere della gestione delle eccezioni a livelli più alti nello stack Future
.
Si noti che questo è simile all'esecuzione del seguente codice in un contesto non Future
:
def runNotFuture: Unit = throw new FairlyStupidException
try {
runNotFuture
} catch {
case e: FairlyStupidException => BadRequest("Another stupid exception!")
}
È molto importante gestire le eccezioni generate all'interno di Future
perché per la maggior parte del tempo sono più insidiose. Di solito non riescono a scappare, perché corrono in un contesto di esecuzione e thread diversi, e quindi non ti chiedono di correggerli quando accadono, specialmente se non noti nulla nei log o il comportamento del applicazione.
Usando le clausole try-catch
Oltre ai costrutti funzionali come Try
, Option
e Either
per la gestione degli errori, Scala supporta anche una sintassi simile a quella di Java, utilizzando una clausola try-catch (con un potenziale blocco finally). La clausola catch è un pattern match:
try {
// ... might throw exception
} catch {
case ioe: IOException => ... // more specific cases first
case e: Exception => ...
// uncaught types will be thrown
} finally {
// ...
}
Convertire le eccezioni in entrambi i tipi di opzioni
Per convertire le eccezioni in tipi Either
o Option
, è possibile utilizzare i metodi forniti in 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 }