优雅的方式处理Scala Map中缺少的键和空值

vin*_*lcy 2 scala

我明白

  • 在Scala中应该避免使用null
  • 和Map.get将返回一个Option [B],我可以使用.getOrElse来获取值并回退到默认值

例如

map.getOrElse("key1","default")
Run Code Online (Sandbox Code Playgroud)

同时我正在与Java库进行交互,其中一些值为null.

例如Map("key1" - > null)

getOrElse 在这种情况下将抛出空指针.

我想处理这两种情况并导致写这样的东西

  def getOrElseNoNull[A,B](map:Map[A,B],key:A,default:B) = {
    map.get(key) match{
      case Some(x) if x != null => x
      case _ => default
    }
  }
Run Code Online (Sandbox Code Playgroud)

这很难看.(它是Map [A​​ny],我需要一个来自该键的字符串)

getOrElseNoNull(map,"key1","").asInstanceOf[String])
Run Code Online (Sandbox Code Playgroud)

是否可以使用隐式来扩展地图,或任何其他优雅的方式?

Rég*_*les 7

如果你正在处理一个不可变的Map,最安全的做法就是预先过滤掉所有的null值(这会导致另一个Map实例的创建,但除非你有特殊的理由关注它的性能)不应该是一个问题).

val withoutNulls = map.filter{case (k,v)=> v != null}
Run Code Online (Sandbox Code Playgroud)

持有null的任何键都消失了,因此getOrElse在此键上将返回None.琐碎,并为所有人做一次工作.


Sea*_*ira 5

救援的隐式扩展类

implicit class NullOccludingMap[K, V](private val underlying: Map[K, V]) extends AnyVal {
  def getNonNullOrElse(key: K, default: V): V = {
    underlying.get(key) match {
      case Some(value) if value != null => value
      case _ => default
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在范围内的任何地方使用它:

val test = Map("x" -> "Hi", "y" -> null)
test.getNonNullOrElse("z", "") // ""
test.getNonNullOrElse("y", "") // ""
Run Code Online (Sandbox Code Playgroud)