Future.filter исключение времени выполнения без каких-либо охранников - PullRequest
0 голосов
/ 21 апреля 2020

Я время от времени получаю util.NoSuchElementException: Future.filter predicate is not satisfied исключений.

Насколько я понимаю из других вопросов, это появляется с if guards в for comprehensions. Я широко использую for comprehensions, но не могу найти никаких условий. Однако я делаю некоторые назначения.

for {
  foo <- Future{0}
  bar = foo + 1
} yield bar

Однако, насколько я понимаю, это должно быть хорошо.

Я изо всех сил пытаюсь найти источник исключения во время выполнения. Есть ли другие случаи, когда Future.filter будет вызван, кроме if guards? Любые другие идеи о том, что я должен искать?

Редактировать:

Может ли это быть вызвано сопоставлением с шаблоном, как

for {
  foo <- Future{0 -> 1}
  (bar, _) <- foo
} yield bar + 1

Edit2:

Полагаю, все вышесказанное хорошо, но это может вызвать RTE?

for {
  (bar, _) <- Future{0 -> 1}
} yield bar + 1

1 Ответ

3 голосов
/ 21 апреля 2020

.filter и .withFilter (ленивая версия, предпочитаемая для понимания) удаляет из ваших F[_] значений, которые не соответствуют предикату:

  • с помощью Списка удаленных значений из List и возвращает List с удаленными значениями
  • с Option, который превращает Some в None, если предикат не выполняется
  • с Try - это похоже на Option, но Success рассматривается как Some, а Failure - как Нет - однако Failure не может быть пустым, и поэтому он помещает туда исключение
  • Будущее асинхронно. Попробуйте.

По этой причине .withFilter(condition) в основном ленивая версия

.flatMap { value =>
  if (condition(value)) => Future.successful(value)
  else Future.failed(new util.NoSuchElementException("Future.filter predicate is not satisfied"))
}

Вы получите это для каждого случая, который вызовет .withFilter в будущем. Для понимания это будет:

  • прямой вызов .withFilter
  • использование предложения if
  • использование сопоставления с шаблоном
for {
  f <- future.withFilter(cond1) // this might raise exception
  g <- makeFuture(f) if cond2 // this might raise
  (head, tail) <- makeFutureList(g) // this might raise
} yield

Чтобы избежать этого (в будущем или других монадах ввода-вывода)

  • не вызывайте withFilter вручную
  • вместо использования if-else:
for {
  value <- future
  success <- if (cond(value)) Future.successful(value)
             else Future.failed(yourOwnError) // handle however you like
} yield success

Вы также можете использовать лучший monadi c, чтобы избежать использования .withFilter при сопоставлении с образцом, который не может быть неудачным (хотя, если они могут потерпеть неудачу, вы все равно получите исключение, так что это не решение, но все же приятно способ избавиться от нежелательного .withFilter).

...