Scala Будущее с фильтром для понимания
В приведенном ниже примере я получаю исключение java.util.NoSuchElementException: Future.filter predicate is not satisfied
Я хочу получить результат Future( Test2 )
, когда проверка if( i == 2 )
завершается с ошибкой. Как обрабатывать фильтр/если он используется для понимания, связанного с составлением фьючерсов?
Ниже приведен упрощенный пример, который работает в Scala REPL.
Код:
import scala.concurrent.Future
import scala.util.{ Try, Success, Failure }
import scala.concurrent.ExecutionContext.Implicits.global
val f1 = Future( 1 )
val f2 = for {
i <- f1
if( i == 2 )
} yield "Test1"
f2.recover{ case _ => "Test2" }
f2.value
Ответы
Ответ 1
В for-comprehension
вы фильтруете i == 2
. Поскольку значение f1
не равно двум, оно не даст значение Success
, а вместо этого Failure
. Предикат фильтра не выполняется, как сообщает ваше сообщение об ошибке. Однако f2.recover
возвращает новый Future
. Значение f2
не обрабатывается. Он по-прежнему сохраняет Failure
. Именно по этой причине вы получаете сообщение об ошибке при вызове f2.value
.
Единственная альтернатива, о которой я могу думать, будет использовать else
в вашем for-comprehension
, как показано здесь.
val f2 = for ( i <- f1) yield {
if (i == 2) "Test1"
else "Test2"
}
f2.value
Это вернет Some(Success(Test2))
, как делает ваш f3.value
.
Ответ 2
Это, по-моему, более идиоматическое решение. Эта предикатная функция создает либо Future[Unit]
, либо неудавшееся будущее, содержащее ваше исключение. Для вашего примера это приведет либо к Success("Test1")
, либо к Failure(Exception("Test2"))
. Это немного отличается от "Test1" и "Test2", но я считаю этот синтаксис более полезным.
def predicate(condition: Boolean)(fail: Exception): Future[Unit] =
if (condition) Future( () ) else Future.failed(fail)
Вы используете его следующим образом:
val f2 = for {
i <- f1
_ <- predicate( i == 2 )(new Exception("Test2"))
j <- f3 // f3 will only run if the predicate is true
} yield "Test1"
Ответ 3
Конечно, я сам разобрался в одном решении. Возможно, есть лучшие, более идиоматические решения?
import scala.concurrent.Future
import scala.util.{ Try, Success, Failure }
import scala.concurrent.ExecutionContext.Implicits.global
val f1 = Future( 1 )
val f2 = for {
i <- f1
if( i == 2 )
} yield "Test1"
val f3 = f2.recover{ case _ => "Test2" }
// OR val f3 = f2.fallbackTo( Future( "Test2" ) )
f3.value