2013-08-15 10 views
28

Was ist der sauberste Weg zu map der Exception eines fehlgeschlagenen Future in scala?Karte die Ausnahme einer fehlgeschlagenen Zukunft

Sagen, ich habe:

import scala.concurrent._ 
import scala.concurrent.ExecutionContext.Implicits.global 

val f = Future { 
    if(math.random < 0.5) 1 else throw new Exception("Oh no") 
} 

Wenn die Zukunft mit 1 erfolgreich ist, würde ich die gerne behalten, aber wenn es nicht ich die Exception auf eine anderen Exception ändern möchte.

Das Beste, was ich tun konnte, Transformation, aber das mir erfordert eine unnötige Funktion für den Erfolgsfall zu machen:

val f2 = f.transform(s => s, cause => new Exception("Something went wrong", cause)) 

Gibt es irgendeinen Grund gibt es keine mapFailure(PartialFunction[Throwable,Throwable]) ist?

+7

Transformation ist der richtige Weg zu gehen. Sie müssen nicht die Funktion s => s erstellen, geben Sie einfach "identity" ein –

+0

Prost. Ich wusste nichts über die Identitätsfunktion. Ich bin mir sicher, dass es mehr Zeiten geben wird, in denen das nützlich sein wird. – theon

Antwort

26

Es auch ist:

f recover { case cause => throw new Exception("Something went wrong", cause) } 

Seit Scala 2,12 Sie tun können:

f transform { 
    case s @ Success(_) => s 
    case Failure(cause) => Failure(new Exception("Something went wrong", cause)) 
} 

oder

f transform { _.transform(Success(_), cause => Failure(new Exception("Something went wrong", cause)))} 
+1

Während dies eine sehr klare Syntax ist, müssen wir immer noch die neue Ausnahme "werfen", anstatt "Throwable" zu "Throwable" zu mappen. Gibt es dafür einen Kombinator? – owensmartin

+0

@owensmartin Siehe meine aktualisierte Antwort. :) –

13

könnten Sie versuchen recoverWith wie in:

f recoverWith{ 
    case ex:Exception => Future.failed(new Exception("foo", ex)) 
} 
+0

Future.failed wird nicht auf einem ExecutionContext ausgewertet: http://www.scala-lang.org/api/current/#scala.concurrent.Future$ siehe '' failed'' –

+0

@ViktorKlang, ich muss dann verwirrt sein. Ich hatte diese Annahme gemacht, indem ich auf die "impl.KeptPromise" -Klasse "onComplete" -Methode schaute. Dort sind die zwei Zeilen 'val preparedEC = executor.prepare; (new CallbackRunnable (preparedEC, func)). executeWithValue (completedAs) '. Ich nahm an, dass dies andeutet, dass, obwohl wir einen expliziten Wert gaben, dass es immer noch aus irgendeinem Grund den Executor traf. Es kam mir immer komisch vor und ich vermute es liegt daran, dass ich es falsch verstanden habe. Danke für die Köpfe hoch. – cmbaxter

+0

Danke für die Antworten. Mein einziges Zögern, 'recover' /' recoverWith' zu verwenden, ist, dass ich sofort davon ausgehe, dass die Absicht darin besteht, sich von einem Fehler mit einem erfolgreichen Ergebnis zu erholen. Vielleicht ist das nur ich. Trotzdem sind sie gute Alternativen, danke! – theon