ОБНОВЛЕНИЕ: я обновил ответ, чтобы исправить мое неправильное понимание вопроса, как указал Тим в своем комментарии.
Как уже упоминалось в моем комментарии, я буду считать, что под «продолжить итерацию» вы подразумеваете просто не выбрасывать исключение и по-прежнему возвращать результаты вплоть до этого момента. Я также предполагаю, что вы хотите поддерживать лень Iterator
.
Если это так, я бы эффективно украсил java.util.Iterator
для защиты от их ошибок, но вернул бы Scala Iterator
, чтобы у вас все еще была лень, что оригинальная библиотека может вам понадобиться. Что-то (не готово к продвижению) на линии:
def scalaIterator[A](it: java.util.Iterator[A]): Iterator[Option[A]] = new Iterator[Option[A]](){
private var hasBoomed: Boolean = false
override def hasNext = !hasBoomed && it.hasNext
override def next() = {
Try(it.next()) match {
case Failure(_) =>
hasBoomed = true
None
case Success(value) => Some(value)
}
}
}
Теперь, при условии, что вы вызываете библиотеку, возвращающую Mailing
экземпляров, вы должны заключить ее в Option
:
val myFuntionalSequence: Iterator[Option[(String, String)]] = for{
mailingOpt <- scalaIterator(thirdPartyIterator)
} yield mailingOpt.map(mailing => (mailing.name, mailing.subject))
Это вернет Iterator[Option[(String, Int)]]
.
Примером результатов может быть (при материализации):
Some(mailing1Pair),Some(mailing2Pair),None // in case of an exception
Some(mailing1Pair),Some(mailing2Pair),Some(mailing3Pair) // no exception
Теперь, что, если вы на самом деле не заботитесь об этом последнем None
? А что, если все, что вам на самом деле нужно, это List[(String, Int)]
, который содержит все успешно возвращенные Mailing
с? В этом случае вы должны сделать:
val flattened: Iterator[(String, String)] = myFuntionalSequence.flatten
Теперь идет действительно функциональная часть;)
Но что, если вы действительно хотите знать, было ли исключение? То есть вы хотите вернуть None
, если было хотя бы одно исключение, или Some (List (someMailing1Pair, etc ....)) в противном случае. По сути, вы хотите преобразовать List[Option[(String, String)]]
в Option[List[(String, String)]]
.
Введите Traverse
из библиотеки Cats:
implicit cats.implicits._
val myFuntionalSeuence: Iterator[Option[(String, String)]] = ...
val flipped: Option[List[(String, String)]] = myFuntionalSeuence.toList.sequence //notice the .toList here: we are materializing a lazy collection here
... в этот момент вы относитесь к нему как к любому другому Option
. Этот подход является общим, он работает со всем, что реализует Traverse
, и я рекомендую вам прочитать документы, на которые я ссылаюсь: вы найдете много вкусностей! :)