Reputation: 892
I have a question about scala's Future
.
Currently I have a program that runs through a directory and checks if there is a document. If there is a file the program should convert these file into a ".pdf"
My Code looks like this (It's pseudocode):
for(file <- directory) {
if(timestamp > filetimestamp) {
Future {
// do a convert job that returns UNIT
}
}
}
Is this valid code or do I need to wait for the return value?
Are there any other alternative's that are as lightweight as Futures?
Upvotes: 3
Views: 4864
Reputation: 786
Warning! If any Future throws a "NonFatal" error, it will be swallowed. This is a serious gotcha when using Future[Unit]: if no code ever evaluates the future, errors can disappear down a black hole. (It affects any Future[_], but if you are returning a value, you normally do something with it, so the error is discovered.)
scala> import scala.concurrent.ExecutionContext.Implicits.global
scala.concurrent.Future { throw new IllegalArgumentException("foo") }
scala> res16: scala.concurrent.Future[Nothing] = scala.concurrent.impl.Promise$DefaultPromise@64dd3f78
scala> import scala.concurrent.ExecutionContext.Implicits.global
scala.concurrent.Future { throw new IllegalArgumentException("foo"); 42 }
scala> res11: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@65c8295b
An alternative which accomplishes the same thing, but does not hide the error:
scala> val context = scala.concurrent.ExecutionContext.Implicits.global
context.execute(new Runnable {
def run() = throw new IllegalArgumentException("foo")
})
context: scala.concurrent.ExecutionContextExecutor = scala.concurrent.impl.ExecutionContextImpl@1fff4cac
scala> | | java.lang.IllegalArgumentException: foo
at $line48.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anon$1.run(<console>:34)
at $line48.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$anon$1.run(<console>:33)
at scala.concurrent.impl.ExecutionContextImpl$$anon$3.exec(ExecutionContextImpl.scala:107)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Upvotes: 7
Reputation: 9135
Yes, that is valid. All the Future
s you create will be run, and their return values will be discarded and garbage collected.
Upvotes: 0
Reputation: 28511
To convert inside a Future
, simply use map
and flatMap
. The actual operations are performed asynchronously when the callbacks are complete, but they are type safe.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
for(file <- directory) {
if(timestamp > filetimestamp) {
val future = Future {
// do a convert job that returns UNIT
} map {
file => // whatever you want.
}
}
Upvotes: 10