我在Jar文件中包含这个Java类作为Scala程序的依赖项(如Axis jar):
class MyClass {
private String[] someStrings;
public String[] getSomeStrings() { return someStrings; }
}
在我的Scala程序中,我有一个Java API,它将MyClass的MyClass实例实例返回给我在Scala中的程序:
val myInstance = JavaAPI.getInstanceOfMyClass()
然后我尝试在我的Scala程序中使用 someStrings 数组,但它是 null (假设它没有正确初始化)
for(str <- myInstance.getSomeStrings()) ...
因此抛出 NullPointerException 。
我发现为了在理解中使用它,我可以将它包装成一个Option,以便它正确处理NPE。
for(str <- Option[Array[String]](myInstance.getSomeStrings).getOrElse(Array[String]())
但这对我来说不太好看。
是否有一种方法可以创建类似于隐式方法,即使它为null并将其包装到Option中,也会获取该值,如:
implicit def wrapNull(a: Null): Option[Nothing] = None
implicit def wrapArray(a: Array[String]): Option[Array[String]] = Some(a)
所以当我这样做时:
for(str <- myInstance.getSomeStrings())
我没有得到 NPE
提前致谢!
答案 0 :(得分:4)
编辑:
map
以及flatMap
始终必须返回相同的类型,并在其上调用它们。如果您有一个列表,您将始终从map
返回一个列表。选项也是如此。如果您尝试在flatMap中混合使用2种类型,则很可能无法正常工作。应该是什么
Some(Array(1,2)).flatMap { x =>
x.map { _ * 2 }
}
返回?有些(2,4)是不可能的。所以你得到一个类型错误。因此,您必须执行嵌套map { map }
而不是flatMap { map }
。
在你的情况下,它会像这样工作:
case class A(b: B)
case class B(c: String)
val result = for(as <- Option(Array(A(B("foo")), A(B("bar"))))) yield {
for(a <- as; b <- Option(a.b); c <- Option(b.c)) yield {
c
}
}
第一个for
需要Option[Array[A]]
并返回Option[Array[String]]
。嵌套for需要Array[A]
并返回Array[String]
。他们都满足monad法则。最后,您可以安全地在getOrElse
上致电result
,以便根据需要解包值。
原:
你可以做到
val result = Option(myInstance.getSomeStrings).map { x =>
x.map { y =>
// do stuff with strings
}
}
或
val result = for(x <- Option(myInstance.getSomeStrings)) yield {
x.map { y =>
// do stuff with strings
}
}
由于类型推断而您不需要编写类型,因此不需要getOrElse
,因为None
不会执行地图。如果需要打开值,则可以在结果上执行getOrElse
。
答案 1 :(得分:3)
我认为您的getOrElse
版本不是那么糟糕(您可以通过删除[Array[String]]
之后的Option
来缩短版本,因为可以推断出这一点。如果你想要更简洁的东西,以下工作:
for (str <- Option(myInstance.getSomeStrings).flatten) ...
您还可以使用Option
具有foreach
:
for {
strings <- Option(myInstance.getSomeStrings)
str <- strings
} ...
请注意,您无法在此处使用yield
,因为drexin会在下面的评论中突出显示。
或者你可以pimp MyClass
:
implicit def withNullWrapper(c: MyClass) = new {
def getSomeStringsOrNot() = Option(c.getSomeStrings).getOrElse(Array[String]())
}
for (str <- myInstance.getSomeStringsOrNot) ...
答案 2 :(得分:2)
简单规则:如果有null
,请将其设为Option
。所以:
for {
array <- Option(myInstance.getSomeStrings)
element <- array
thingy <- Option(element.method)
} yield thingy
只有这样才行不通。由于array
,它会返回多个元素,但由于第一个生成器是Option
,它将返回Option
。这两个元素是不利的:您不能返回多个元素的Option
。
解决问题的最简单方法是将Option
转换为迭代器或集合(根据您的喜好)。像这样:
for {
array <- Option(myInstance.getSomeStrings).toSeq
element <- array
thingy <- Option(element.method)
} yield thingy
请注意,不需要触及第二个Option
:导致问题的是第一个生成器。 Option
除了第一个生成器之外的任何地方都不是问题。