2013-08-15 17 views
28

Jaki jest najczystszy sposób na map z Exception nieudanego Future w scala?Mapowanie wyjątku nieudanej przyszłości

Say mam:

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

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

Jeśli przyszłości uda się 1, chciałbym zachować to, jednak, jeśli nie chciałabym zmienić Exception do innego Exception.

Najlepszym mogłem wymyślić jest przekształcić jednak, że wymaga mi zrobić niepotrzebnych funkcji dla przypadku sukcesu:

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

Czy jest jakiś powód, nie ma mapFailure(PartialFunction[Throwable,Throwable])?

+7

Transform to właściwa droga. nie musisz tworzyć funkcji s => s, po prostu przekazuj w "tożsamości" –

+0

Pozdrawiam. Nie wiedziałem o funkcji "tożsamości". Jestem pewien, że będzie więcej razy, kiedy to się przyda. – theon

Odpowiedz

26

Istnieje również:

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

Od Scala 2.12 można zrobić:

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

lub

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

Chociaż jest to bardzo przejrzysta składnia, wciąż musimy "rzucić" nowy wyjątek zamiast zamieniać 'Throwable' na' Throwable'. Czy istnieje właśnie kombinator? – owensmartin

+0

@owensmartin Zobacz moją zaktualizowaną odpowiedź. :) –

13

można spróbować recoverWith jak w:

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

Future.failed nie jest oceniany w ExeecutionContext: http://www.scala-lang.org/api/current/#scala.concurrent.Future$ patrz '' failed'' –

+0

@ViktorKlang, muszę się wtedy pomylić. Założyłem to założenie patrząc na metodę 'impl.KeptPromise'' 'onComplete'. Tam są dwie linie 'val prepareEC = executor.prepare; (nowy CallbackRunnable (preparedEC, func)). executeWithValue (completeAs) '. Zakładałem, że to sugeruje, że mimo iż dawaliśmy wyraźną wartość, to z jakiegoś powodu uderzało w wykonawcę. Zawsze wydawało mi się to dziwne i wydaje mi się, że tak jest, ponieważ błędnie to odczytałem. Dzięki za heads up. – cmbaxter

+0

Dzięki za odpowiedzi. Moje jedyne wahanie w używaniu 'recover' /' recoverWith' jest takie, że gdy je zobaczę, natychmiast zakładam, że celem jest odzyskanie po niepowodzeniu z pomyślnym wynikiem. Może to tylko ja. Mimo to są dobrymi alternatywami, dzięki! – theon