作为文章的结果,我阅读了有助于避免NullPointerException的Option
类,我开始在整个地方使用它。想象一下这样的事情:
var file:Option[File] = None
以后我使用它时:
val actualFile = file.getOrElse(new File("nonexisting"))
if(actualFile.getName.equals("nonexisting")) { // instead of null checking
}
else { // value of file was good
}
做这样的事情对我来说感觉不那么“正确”。我还注意到.get
已被弃用。 。这种东西是你们用Option做的,或者我走错了路?
答案 0 :(得分:15)
返回Option
然后使用getOrElse
生成一些意味着“未找到”的哨兵值通常不是一个好主意。这就是Option
的目的:表示找不到值!
Option
在与map
和foreach
等函数式编程结构结合使用时,确实显示了它的强大功能。在处理多个选项时,这是最有效的。例如,假设我编写了一个接受字符串并返回文件的方法,但仅当文件存在且文件不是目录时才会显示:
import java.io._;
def niceFile1(s: String): File = {
val f = new File(s);
if (f.exists && !f.isDirectory) f else null
}
def niceFile2(s: String): Option[File] = {
val f = new File(s);
if (f.exists && !f.isDirectory) Some(f) else None
}
到目前为止,使用null
更容易 - 至少在您忘记这可能会给您null
并且您获得NPE之前。无论如何,我们现在尝试使用它。
def niceFopen1(s: String) = {
val f = niceFile1(s);
if (f!=null) new FileInputStream(f) else null;
}
def niceFopen2(s: String) = niceFile2(s).map(f => new FileInputStream(f))
看看发生了什么!在前一种情况下,我们必须手动进行逻辑测试并创建临时变量。啊!在第二种情况下,map
为我们完成了所有脏工作:无映射到无,Some(file)
映射到Some(fileinputstream)
。简单!
但它变得更好了。也许我们想找到一大堆文件的大小:
def totalSize2(ss: Seq[String]) = {
(0L /: ss.flatMap(niceFile2)){(sum,f) => sum+f.length}
}
等等,这里发生了什么 - 所有None
怎么样?我们不是必须注意并以某种方式处理它们吗?好吧,那就是flatMap
进来的地方:它将所有答案连接在一起。 None
是零长度的答案,所以它忽略了它。 Some(f)
有一个答案 - f
- 所以它将它放在列表中。然后我们使用折叠来累加所有长度 - 现在列表中的所有元素都是有效的。太好了!
答案 1 :(得分:12)
不能解析 Option
的值,但将逻辑应用于其中包含的内容
findFile.foreach(process(_))
基本上,如果找到一个File
,则处理for
,否则不会执行任何操作(并且等同于Thomas'for
理解,因为foreach
编译为findFile match {
case Some(f) => process(f)
case None =>
}
的调用)。这是一个更简洁的版本:
(findLiveFile orElse fileBackupFile orElse findTempFile).foreach(process(_)
更重要的是,关于这一点的好处是你可以链操作,例如:
{{1}}
答案 2 :(得分:7)
在大多数情况下,您会使用模式匹配
file match {
case Some(f) => { .. } //file is there
case _ => { .. } //file is not there
}
如果您只对该文件感兴趣,可以使用for表达式
for(f <- file) { //file is there
}
然后,您可以链接表达式以在容器上的多个级别上工作
for{
option <- List(Some(1), None, Some(2))
f <- option
} yield f
res0: List[Int] = List(1, 2)
或者你可以使用isDefined并获取:
if(option.isDefined) {
val x = option.get;
} else {
}
在Scala 2.8.0.Beta-1中不推荐使用get。
答案 3 :(得分:2)
这是另一种选择:
var file:Option[File] = None
// ...
file map (new File(_)) foreach { fh =>
// ...
}
但是,如果您需要在文件存在时执行某些操作,而如果不存在则需要执行其他操作,则match
语句更合适:
var file:Option[File] = None
// ...
file map (new File(_)) match {
case Some(fh) =>
// ...
case None =>
// ...
}
这与if
语句几乎相同,但我喜欢它更好地为Option
这样的事物链接自然,我想在那里提取一个值。
答案 4 :(得分:1)
主要重述每个人都在说什么,但我认为当你有一个像这样可以为零的var时,你会遇到至少4种不同的情况:
1.文件不能为空
load(file.get())
当您尝试实际使用该文件时将抛出异常。快失败,耶!
2.该文件为空,但在这种情况下,我们有一个合理的默认值:
load(file.getOrElse(new File("/defaultFile")))
3.基于文件是否存在的两个逻辑分支:
file match {
case Some(f) => { .. } //file is there
case _ => { .. } //file is not there
}
4.如果文件为空,则为无操作,即静默失败。在现实生活中,我不认为这个经常适合我:
for (f <- file) {
//do some stuff
}
或者,也许更清楚?
if (f.isDefined) {
//do some stuff
}