Вы можете использовать команду ниже, чтобы лучше понять, что делает компилятор Scala под капотом:
$ scalac -Xprint:typer MainClass.scala
«Первый» будет переведен в:
scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(3000L); scala.Predef.println("a")
})(scala.concurrent.ExecutionContext.Implicits.global)
.foreach[Unit](((_: Unit) =>
scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(2000L); scala.Predef.println("b")
})(scala.concurrent.ExecutionContext.Implicits.global)
.foreach[Unit](((_: Unit) => scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(1000L); scala.Predef.println("c")
})(scala.concurrent.ExecutionContext.Implicits.global)
.foreach[Unit](((_: Unit) => ()))(scala.concurrent.ExecutionContext.Implicits.global)))(scala.concurrent.ExecutionContext.Implicits.global)))
(scala.concurrent.ExecutionContext.Implicits.global);
«Второй» в
val future1: scala.concurrent.Future[Unit] = scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(3000L);
scala.Predef.println("a")
})(scala.concurrent.ExecutionContext.Implicits.global);
val future2: scala.concurrent.Future[Unit] = scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(2000L);
scala.Predef.println("b")
})(scala.concurrent.ExecutionContext.Implicits.global);
val future3: scala.concurrent.Future[Unit] = scala.concurrent.Future.apply[Unit]({
java.lang.Thread.sleep(1000L);
scala.Predef.println("c")
})(scala.concurrent.ExecutionContext.Implicits.global);
{
future1.flatMap[Unit](((_: Unit) => future2.flatMap[Unit](((_: Unit) => future3.map[Unit](((_: Unit) => ()))(scala.concurrent.ExecutionContext.Implicits.global)))(scala.concurrent.ExecutionContext.Implicits.global)))(scala.concurrent.ExecutionContext.Implicits.global);
()
}
В случае «Первого» следующее Будущее будет создано внутри «.foreach» первого Будущего и т. Д.
Во втором случае сначала будут созданы все 3 фьючерса, выполненные параллельно, а затем в виде flatMap.