Scala Language
Foutafhandeling
Zoeken…
Proberen
Met Probeer met map
, getOrElse
en 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)
Gebruik Try
met patroonovereenkomst:
Try(parsePerson("John Doe")) match {
case Success(person) => println(person.surname)
case Failure(ex) => // Handle error ...
}
Een van beide
Verschillende gegevenstypen voor fouten / succes
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")
}
}
Patroonovereenkomst op beide waarden
getPersonFromWebService("http://some-webservice.com/person") match {
case Left(errorMessage) => println(errorMessage)
case Right(person) => println(person.surname)
}
Zet beide waarden om in Optie
val maybePerson: Option[Person] = getPersonFromWebService("http://some-webservice.com/person").right.toOption
Optie
Het gebruik van null
waarden wordt sterk afgeraden, tenzij interactie met legacy Java-code die null
verwacht. In plaats daarvan moet Option
worden gebruikt wanneer het resultaat van een functie iets ( Some
) of niets ( None
) kan zijn.
Een try-catch-blok is geschikter voor het afhandelen van fouten, maar als de functie legitiem niets kan retourneren, is Option
geschikt en eenvoudig.
Een Option[T]
kan Some(value)
(bevat een waarde van type T
) of None
:
def findPerson(name: String): Option[Person]
Als er geen persoon wordt gevonden, kan None
worden geretourneerd. Anders wordt een object van het type Some
met een Person
object geretourneerd. Wat volgt zijn manieren om een object van het type Option
.
Patroon matching
findPerson(personName) match {
case Some(person) => println(person.surname)
case None => println(s"No person found with name $personName")
}
Kaart gebruiken en getOrElse
val name = findPerson(personName).map(_.firstName).getOrElse("Unknown")
println(name) // Prints either the name of the found person or "Unknown"
Gebruik vouw
val name = findPerson(personName).fold("Unknown")(_.firstName)
// equivalent to the map getOrElse example above.
Converteren naar Java
Als u een Option
naar een ongeldig Java-type moet converteren voor interoperabiliteit:
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
Fouten verwerken die afkomstig zijn van futures
Wanneer een exception
wordt gegooid vanuit een Future
, kunt u (moeten) recover
gebruiken recover
te handelen.
Bijvoorbeeld,
def runFuture: Future = Future { throw new FairlyStupidException }
val itWillBeAwesome: Future = runFuture
... gooit een Exception
vanuit de Future
. Maar aangezien we kunnen voorspellen dat een Exception
van het type FairlyStupidException
met een grote waarschijnlijkheid, we dit geval op een elegante manier kunnen behandelen:
val itWillBeAwesomeOrIllRecover = runFuture recover {
case stupid: FairlyStupidException =>
BadRequest("Another stupid exception!")
}
Zoals je kunt zien, is de methode die wordt gegeven om te recover
een PartialFunction
over het domein van alle Throwable
, dus je kunt slechts een paar soorten verwerken en de rest vervolgens in de ether van uitzonderingsafhandeling op hogere niveaus in de Future
stapel laten gaan.
Merk op dat dit vergelijkbaar is met het uitvoeren van de volgende code in een niet- Future
context:
def runNotFuture: Unit = throw new FairlyStupidException
try {
runNotFuture
} catch {
case e: FairlyStupidException => BadRequest("Another stupid exception!")
}
Het is echt belangrijk om uitzonderingen te verwerken die binnen Future
s zijn gegenereerd, omdat ze meestal verraderlijker zijn. Ze krijgen meestal niet alles in je gezicht, omdat ze in een andere uitvoeringscontext en thread worden uitgevoerd, en dus niet je vragen om ze te repareren wanneer ze gebeuren, vooral als je niets in logs of het gedrag van de toepassing.
Try-catch-clausules gebruiken
Naast functionele constructies zoals Try
, Option
en Either
voor foutafhandeling, ondersteunt Scala ook een syntaxis vergelijkbaar met die van Java, met behulp van een try-catch-clausule (met een potentieel slotblok ook). De vangclausule is een patroonovereenkomst:
try {
// ... might throw exception
} catch {
case ioe: IOException => ... // more specific cases first
case e: Exception => ...
// uncaught types will be thrown
} finally {
// ...
}
Converteer uitzonderingen naar een van beide of optietypen
Om uitzonderingen te zetten in Either
of Option
types, kunt u methoden die voorzien in het gebruik 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 }