假设我有一个List(或Map中的值),我想对每个项目执行操作。但不幸的是,无论出于何种原因,这个值列表都可以包含空值。
scala> val players = List("Messi", null, "Xavi", "Iniesta", null)
players: List[java.lang.String] = List(Messi, null, Xavi, Iniesta, null)
为了避免炸毁NPE,我需要做以下事情:
scala> players.filterNot(_ == null ).map(_.toUpperCase)
res84: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
有没有更好的方法呢?
理想情况如下:
players.safeMap(_.toUpperCase)
在scala-language mailing list上,西蒙提出了这个建议:
players.filter ( null !=).map(_.toUpperCase )
这是我原始版本的缩短版本,并且只要没有专用方法就可以获得。
更好的是,Stefan和Kevin提出了方法withFilter,它将返回一个惰性代理,因此两个操作都可以合并。
players.withFilter ( null !=).map(_.toUpperCase )
答案 0 :(得分:3)
如果您无法避免null
(例如,如果从Java代码中获取列表),另一种方法是使用collect
代替map
:
scala> players.collect { case player if player != null => player.toUpperCase }
res0: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
答案 1 :(得分:2)
我会这样做:
players flatMap Option map (_.toUpperCase)
但这比collect
更糟糕。使用filter
,map
+ collect
总是更好。
答案 2 :(得分:1)
您可以转换为Option[String]
的列表:
scala> val optionPlayers = players.map(Option(_))
optionPlayers: List[Option[java.lang.String]] = List(Some(Messi), None, Some(Xavi), Some(Iniesta), None)
Option
普遍优先于null
,它为您提供了如何安全处理数据的灵活性。以下是获得所需结果的简便方法:
scala> optionPlayers.collect { case Some(s) => s.toUpperCase }
res0: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
scala> optionPlayers.flatMap(_.map(_.toUpperCase))
res1: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
scala> optionPlayers.flatten.map(_.toUpperCase)
res2: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
您可以在其他StackOverflow问题中或通过搜索网络找到有关Option
的更多信息。
或者,您始终可以将safeMap
方法定义为隐含在List
上的implicit def enhanceList[T](list: List[T]) = new {
def safeMap[R](f: T => R) = list.filterNot(_ == null).map(f)
}
方法:
scala> players.safeMap(_.toUpperCase)
res4: List[java.lang.String] = List(MESSI, XAVI, INIESTA)
所以你可以这样做:
CanBuildFrom
虽然如果你定义一个隐式的,你可能想要使用像基本集合那样的List
样式,使它不仅仅是{{1}}。您可以在其他地方找到更多相关信息。