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
The simplest way to create a future object is to invoke the Future. apply method which starts an asynchronous computation and returns a future holding the result of that computation. The result becomes available once the future completes.
The Promise is a writable, single-assignment container that completes a Future. The Promise is similar to the Future. However, the Future is about the read-side of an asynchronous operation, while the Promise is about the write-side.
This Future. sequence() function converts a list of Futures into a single Future that means collections of Futures into a single Future. In simple words, List[Future[T]] ======> Future[List[T]] . It is also known as composing Futures.
Await. result tries to return the Future result as soon as possible and throws an exception if the Future fails with an exception while Await. ready returns the completed Future from which the result (Success or Failure) can safely be extracted.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With