Reputation: 521
I wonder the difference between onComplete and foreach when we use a Future in Scala.
f onComplete (_ => doSomething(_))
and
f foreach (_ => doSomething(_))
Do the above lines of code lead to the same result?
If I want to doSomething with Future f only after it's completed. What should I do? Should I use isCompleted like this:
if(f.isCompleted) f onComplete (_ => doSomething(_))
Thank you guys a lot
Upvotes: 13
Views: 7370
Reputation: 5556
The main difference is the onComplete
callback gets called even if the future completes with a failure, while foreach
(and onSuccess
) functions are called only in case of a successful result.
In fact, onComplete
's parameter is a function Try[T] => U
: the function you pass will be called with a Success[T]
as argument if the future is successful or with a Failure
if there was an exception:
val f = Future { ??? } // this future completes with a failure
// foreach only calls the callback if the future is successful
f.foreach(_ => thisWillNeverExecute())
// This will print "future failed" after the future completes
f.onComplete {
case Success(_) => println("future completed successfully")
case Failure(e) => println("future failed")
}
Also, you don't need to check anything to call the mentioned methods: onComplete
/onSuccess
/onFailure
/foreach
all schedule a callback that is called on the implicit ExecutionContext
you have in scope, only when the future completes.
You can call them even if isCompleted
is false, they will only be executed when the future completes successfully or fails, depending on which one you chose.
Let's have a look at their signatures:
def onComplete[U](@f: Try[T] => U)(implicit executor: ExecutionContext): Unit
onComplete
takes a Try[T] => U
function: this function will be executed on the implicit executor
when the future completes. The argument will either be a Success[T]
if the future is successful or a Failure
if the future is faileddef onFailure[U](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit
onFailure
parameter is a PartialFunction
that is only executed on the implicit executor
if the future fails with a Throwable
for which pf
is defined. It's basically the same as calling onComplete matching only some Failure
s, and in fact that is exactly how it is implemented in the standard library.def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit
onSuccess
parameter is, symmetrically to onFailure
, a PartialFunction
that is only executed on the implicit executor
if the future completes successfully and the supplied PartialFunction
is defined for the value. def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit
foreach
is basically the same as onSuccess
but it takes a total function. This means that f
is always executed if the Future completes successfullyN.B.: 'onSuccess' and 'onFailure' are going to be deprecated in 2.12. I suggest you read this series of posts by Viktor Klang to find out how you will be affected by the changes
Upvotes: 22