Практика код#
Вычисление суммы без использования буфера#
Пример, где подсчитывается сумма по записям коллекции Oil_PlanFactoryShipPos:
//получаем все записи коллекции по родителю (объект rop)
Oil_PlanFactoryShipPosApi().byParent(rop)
//получаем только значение поля nQtyLoad
//в случае незаполненности поля необходимо иметь значение 0, иначе в дальнейшем сумма с null = null
.map(_.get(_.nQtyLoad).nvl(0.nn))
//сложение, результат которого будет обернут безопасной конструкцией Option
.reduceOption(_ + _)
//распаковка Option
//если внутри был null или в коллекции не было записей, то вернётся указанное значение 0.nn
.getOrElse(0.nn)
Группировка объектов с использованием null-типов#
При группировке объектов коллекций, в которых используется null-типы нужно учитывать, что метод groupBy считает хэши группируемых объектов,
поэтому перед группировкой, нужно убедиться, что параметр, используемый для группировки, не равен null.
Пример, с NPE:
List(
asd(123.nl, "asd".ns),
asd(None.nl, "asd".ns), // У NLong с underlying = null хэш не посчитается
).groupBy(_.id).foreach { case (_, name) =>
println(name)
}
Перед использованием groupBy необходимо отфильтровать значения или использовать метод nvl, либо группироваться по Option[?] использовав метод option.
Для дальнейшего использования Nullable, участвовавших в уникальном ключе есть несколько вариантов.
Коллекции с сортировкой для простых Nullable
Пример:val avIdEiToRop = ropa.view.map(r => r.get(_.idExpenceItem) -> r).to(mutable.SortedMap) avIdEiToRop.get(None.nl).foreach { ropInDim => }
При создании коллекций в scala с уникальным ключом возможны варианты использования:
отсортированной коллекции, имеющей обычно префикс Sorted или Tree, например,
collection.SortedMap,collection.immutable.TreeMapколлекции, для определения уникальности обращающейся к методу hashCode с сравнением результата для определения уникальности. Такие классы используются в часто вызываемых методах: фабричных (
mutable.Map.empty,mutable.HashMap), группировки (ropa.groupBy(_.get(_.gidObjCalc)),immutable.HashMap), toMap, toSet.Взамен применения Hash коллекций, вызывающих
hashCode, ведущий к NPE, возможно использование Sorted, для чего важно наличие способа упорядочивания для типа (Ordering, что сейчас отсутствует для NGid):ropa.view.map(r => r.get(_.gidObjCalc)).to(collection.SortedSet) // compile error
Tuple с nvl и nullif
Пример:
for (((idvEI, gidvOC), ropa) <- ropa.groupBy(_ :> (aro => aro.idExpenceItem.nvl(0) -> aro.gidObjCalc.nvl("0".ng)))) { val idvUsedEI = idvEI.nullif(0) val idvUsedOC = gidvOC.nullif("0".ng) }
В чем есть неудобство при более чем одном обращении к ключу.
case class с переопределённым hashCode
Пример:
case class Key(gidObjCalc: NGid, idBisObj: NLong) { override lazy val hashCode: Int = { def hvl(p: Nullable[_, _]) = if (p.isNull) -1.nl else p util.hashing.MurmurHash3.orderedHash(Seq(hvl(gidObjCalc), hvl(idBisObj))) } } case class Det() val avKeyToDet = mutable.Map.empty[Key, mutable.Buffer[Det]] // Заполнение avKeyToDet for ((vKey, avDet) <- avKeyToDet) { processDim(vKey.gidObjCalc, vKey.idBisObj) // прямо без nullif }
В чем отсутствует недостаток постоянного написания nullif и nvl. Запись hashCode однотипная, шаблонная. В случае хэша lazy val всех входящих свойств важно указание как val констант.
Сравнение диапазона дат#
Допустим документы имеют поля dBeginDoc и dEndDoc.
Фильтр имеет 2 поля dBeginFilter и dEndFilter.
Чтобы найти все документы, которые началом или окончанием входят в диапазон, указанный в фильтре, нужно использовать следующее условие:
dBeginDoc <= dEndFilter && dEndDoc >= dBeginFilter
.distinct или .toSet для scala-коллекций и особенности применения#
Если необходимо в scala-коллекции держать только уникальные объекты, можно использовать методы:
.distinct;.toSet.
Перед использованием метода .distinct scala-коллекцию необходимо подготовить: убрать значения null. Иначе в ходе выполнения программы выпадет ошибка java.lang.NullPointerException.
Пример использования и демонстрация поведения методов:
test("distinctOrToSet") {
val data: Seq[NString] = Seq("h".ns, "i".ns, "i".ns, None.ns, None.ns)
println("Результат работы .distinct с null внутри scala-коллекции:")
try {
println(data.distinct)
} catch {
case e: Throwable => println("Ошибка:\n" + "java.lang.NullPointerException")
} finally {
println("\nРезультат работы .filter(_.isNotNull).distinct:")
println(data.filter(_.isNotNull).distinct)
try {
println("\nРезультат работы .toSet с null внутри scala-коллекции:")
println(data.toSet)
} catch {
case e: Throwable => println("Ошибка:\n" + "java.lang.NullPointerException\n")
}
}
}
Результат:
Примечание
Результат работы .distinct с null внутри scala-коллекции: Ошибка: java.lang.NullPointerException
Результат работы .filter(_.isNotNull).distinct: List(h, i)
Результат работы .toSet с null внутри scala-коллекции: Set(h, i, Null)
immutable.Map.builder вместо mutable.Map#
Если по результату сформированной Map она больше не изменяется, то для формирования лучше использовать конструктор immutable.Map.builder, чем mutable.Map.
Пример:
val map = Map.newBuilder[NString, NString]
map ++= Map("1" -> "11")
map += "2" -> "22"
map.result() //Map("1" -> "11", "2" -> "22")
Признак наличия модуля на проекте#
val isInstallProModule = session.sbtClassLoader.getModuleMap.containsKey("pro")
Вернёт true, если такой модуль есть в проекте, иначе false.
Предупреждение
Поддержка этого метода не гарантируется.
Применение ASQL/ ASelect/ OQuery/ TxIndex/ refreshByParent и byParent#
Про данные инструменты можно почитать здесь.