#scala
#scala
Вопрос:
Я работаю с scala и недавно унаследовал некоторый Java-код, который необходимо внедрить, и, к сожалению, переписать его в Scala не в карточках. Он имеет глубоко вложенную структуру объектов, и любой уровень может быть нулевым. Часто меня интересуют только значения глубоко внутри вложенности.
В идеале я бы сделал что-то вроде этого:
Option(foo.blah.blarg.doh)
Но если какой-либо из foo.blah.blarg имеет значение null, это приведет к созданию NPE.
На данный момент я решил обернуть это попыткой:
Try(Option(foo.blah.blarg.doh)).getOrElse(None)
Обратите внимание, что использование .toOption работает не совсем правильно, поскольку это может привести к Some(null), если последний бит цепочки равен null.
Мне не особенно нравится эта конструкция, есть еще какие-нибудь идеи?
Комментарии:
1. если вы можете использовать scalaz, то это облегчит вам работу с exception монадическим способом и получение сообщения об исключении. def yourMethod = /.fromTryCatch { Option(foo.blah.blarg.doh) } где
yourMethod
возвращает дизъюнкцию `/[Throwable,Option[T]]
Ответ №1:
Плоская карта:
for {
a <- Option(foo)
b <- Option(a.blah)
c <- Option(b.blarg)
d <- Option(c.doh)
} yield d
Комментарии:
1. Я понимаю, что FTS как фраза сама по себе идиоматична 🙂 — однако это тот случай, когда я не так сильно копаюсь в этом. Таких конечных точек много, и для каждой из них потребуется несколько строк кода, чтобы добраться до них с помощью этого механизма. Если бы был способ обобщить этот шаблон, чтобы он был записан один раз и использовался где угодно (включая разные гнезда и т. Д.) Мне бы это понравилось намного больше, но это выходит за рамки моего scala-fu.
2. с помощью динамических макросов вы могли бы преобразовать что-то вроде
DynAccess(foo).blah.blarg.doh
в a для понимания / некоторых нулевых проверок. Но у меня нет времени писать это в данный момент.
Ответ №2:
Воспользуйтесь параметрами по имени для создания собственной конструкции:
def handleNull[T](x: => T): Option[T] = try Option(x) catch {
case _: NullPointerException => None
}
handleNull(foo.blah.blarg.doh)
Ответ №3:
Если cats
в вашем проекте есть библиотека, вы можете использовать ее методы расширения:
import cats.implicits._
Either
.catchOnly[NullPointerException](foo.blah.blarg.doh)
.collectFirstSome(Option(_))
Ответ №4:
Вы также можете использовать этот метод для безопасного перемещения по цепочке вызовов, где каждый шаг может возвращать значение null. Его удобнее использовать, чем Options и flatMaps.
/**
* @param expr expression which is a chain of java calls
* @tparam A the type of the last expression
* @return Some(A) if there was no null, None otherwise
*/
def safeTraverseNullableChain[A](expr: => A): Option[A] = {
Try(expr).filter(_ != null).toOption
}