scala中的option[T]、Any、Nothing、Null、null、Nil、None和Unit
1 Option[T] 、 None 和 Some
Option定义:
package scala
@scala.SerialVersionUID(value = -114498752079829388)
sealed abstract class Option[+A]() extends scala.AnyRef with scala.Product with scala.Serializable {
...
}
object Option extends scala.AnyRef with scala.Serializable {
implicit def option2Iterable[A](xo : scala.Option[A]) : scala.Iterable[A] = { /* compiled code */ }
def apply[A](x : A) : scala.Option[A] = { /* compiled code */ }
def empty[A] : scala.Option[A] = { /* compiled code */ }
}
Option[T]主要是用来避免NullPointerException异常的(Option本身是一个容器)
object Test {
def main(args: Array[String]): Unit = {
val option1: Option[Int] = Some(2018)
val option2: Option[Int] = None
val v1 = option1.getOrElse(0)
println(v1)//输出:2018
val v2 = option2.getOrElse(0)
println(v2)//输出: 0
//我们明确知道option1是有值的
val v3 = option1.get
println(v3)//输出:2018
val map:Map[Int,String] = Map(1 -> "aaa", 2 -> "bbbb", 3 -> "cccc")
//根据key获取map中的值,map中的value都是一个Option
val v4:Option[String] = map.get(1)
println(v4)//输出:Some(aaa)
//根据key获取map中的值,并求出值的长度
println(map.get(1).getOrElse("").length())//输出:3
println(map.get(10).getOrElse("").length())//输出:0
println(map.get(10))//输出:None
//检测Option容器中的元素是否为 None
println(map.get(1).isEmpty)//输出:false
println(map.get(10).isEmpty)//输出:true
}
}
Option定义了getOrElse方法,在获取容器中的值是如果有返回容器中的值,如果没有就返回给定的值,这一点和Java8的一样。
Option定义了get方法,直接获取容器中的元素,该操作不安全,可能会遇到None,None调用get就会出现空指针异常
Option定义了isEmpty方法,可以判断容器中是不是None
Option的apply()方法可以返回None/Some可知None或Some必定是Option的子类,None与Some源码
None 源码
package scala
@scala.SerialVersionUID(value = 5066590221178148012)
case object None extends scala.Option[scala.Nothing] with scala.Product with scala.Serializable {
def isEmpty : scala.Boolean = { /* compiled code */ }
def get : scala.Nothing = { /* compiled code */ }
}
Some源码
package scala
@scala.SerialVersionUID(value = 1234815782226070388)
final case class Some[+A](val value : A) extends scala.Option[A] with scala.Product with scala.Serializable {
def isEmpty : scala.Boolean = { /* compiled code */ }
def get : A = { /* compiled code */ }
@scala.deprecated("Use .value instead.", "2.12.0")
def x : A = { /* compiled code */ }
}
Option的常用方法:
序号 | 方法及描述 |
---|---|
1 | def get: A 获取可选值 |
2 | def isEmpty: Boolean 检测可选类型值是否为 None,是的话返回 true,否则返回 false |
3 | def productArity: Int 返回元素个数, A(x_1, ..., x_k), 返回 k |
4 | def productElement(n: Int): Any 获取指定的可选项,以 0 为起始。即 A(x_1, ..., x_k), 返回 x_(n+1) , 0 < n < k. |
5 | def exists(p: (A) => Boolean): Boolean 如果可选项中指定条件的元素存在且不为 None 返回 true,否则返回 false。 |
6 | def filter(p: (A) => Boolean): Option[A] 如果选项包含有值,而且传递给 filter 的条件函数返回 true, filter 会返回 Some 实例。 否则,返回值为 None 。 |
7 | def filterNot(p: (A) => Boolean): Option[A] 如果选项包含有值,而且传递给 filter 的条件函数返回 false, filter 会返回 Some 实例。 否则,返回值为 None 。 |
8 | def flatMap[B](f: (A) => Option[B]): Option[B] 如果选项包含有值,则传递给函数 f 处理后返回,否则返回 None |
9 | def foreach[U](f: (A) => U): Unit 如果选项包含有值,则将每个值传递给函数 f, 否则不处理。 |
10 | def getOrElse[B >: A](default: => B): B 如果选项包含有值,返回选项值,否则返回设定的默认值。 |
11 | def isDefined: Boolean 如果可选值是 Some 的实例返回 true,否则返回 false。 |
12 | def iterator: Iterator[A] 如果选项包含有值,迭代出可选值。如果可选值为空则返回空迭代器。 |
13 | def map[B](f: (A) => B): Option[B] 如果选项包含有值, 返回由函数 f 处理后的 Some,否则返回 None |
14 | def orElse[B >: A](alternative: => Option[B]): Option[B] 如果一个 Option 是 None , orElse 方法会返回传名参数的值,否则,就直接返回这个 Option。 |
15 | def orNull 如果选项包含有值返回选项值,否则返回 null。 |
2 Any
Any是abstract类,它是Scala类继承结构中最底层的。所有运行环境中的Scala类都是直接或间接继承自Any这个类,它就是其它语言(.Net,Java等)中的Object。
Any 处于类型结构树的根部位置,Any 没有父类,但有三个子类:
AnyVal, 价值类型和价值类的父类。
AnyRef,所有引用类型的父类。
•通用特征(universal trait)。
AnyVal 有九个具体子类,称为值类型。其中七个是数字值类型:Byte、Char、Short、Int、Long、Float 和Double。余下的两个是非数字值类型,Unit 和Boolean。
除AnyVal及其子类外,其他类型均为引用类型。它们派生自AnyRef,AnyRef 是java.lang.Object的别名。在Java 的对象模型中,Object 并没有一个封装了原生类型和引用类型的父类,因为Java 对原生类型做了特殊处理。
3.Nothing
Nothing是所有其他类型的子类
Nothing 在Java 中没有类似的概念,但它填补了存在于Java 类型系统中的空白。Nothing 在编译器里的实现相当于以下声明:
package scala
abstract final class Nothing extends Any
Nothing 实际上继承了Any。根据类型系统里的构造规则,Nothing 是所有其他类型的子类,无论是引用类型还是值类型。换句话说,Nothing 继承了所有一切(everything),这让它的名字听起来很奇怪。
Nothing 没有实例,Nothing 为类型系统提供了两种功能:
1、用来当做Nil的类型List[Nothing]
package scala.collection.immutable
object Nil extends List[Nothing] with Product with Serializable
Nil表示一个空的list,与list中的元素类型无关,他可以同时表示List[任意类型]的空集合。
2、Nothing 用来表示终止程序,非正常类型的返回值类型
我们可以临时调用??? 方法来定义其他的方法,使得方法定义完整,并通过编译。但如果调用该方法,就会抛出异常。以下是??? 的定义:
package scala
object Predef {
...
def ??? : Nothing = throw new NotImplementedError
...
}
4.Null与null
Null 对于大多数语言而言是个熟悉的概念。尽管这些语言通常并没有定义Null 类型,仅仅定义了关键字null,用于向引用变量赋值,表示该变量实际上没有值。Null 在编译器里的实现相当于以下声明:
package scala
abstract final class Null extends AnyRef
该声明不允许子类派生以及创建实例,但运行时环境提供了一个实例,就是我们最熟悉的、最喜爱、最可恶的null,我们在创建实例时仅仅是想声明一下变量,暂时不创建实例,这是很容易想到null对象,有了它我们就可以顺利编写程序了,所以null是我们最熟悉、最喜爱的实例,所谓乐极生悲,爱极必反,null也不例外,他也是空指针的万恶之源,所以他也是最可恶的实例。
Null 被明确定义为AnyRef 的一个子类型,但它也是所有AnyRef 类型的子类型。这是类型系统允许你用null 给任何引用类型赋值的正常做法。另一方面,因为null 不是AnyVal 的子类型,所以不可以用null 给Int 赋值。于是,Scala 的null 与Java 的null 完全相同,因为它必须与Java 的null 共存于JVM。否则,Scala 会破坏null 的概念,引起很多潜在的bug。
5、Nil
Nil是Scala声明一个空列表的专用类型,它是继承了List[Nothing] 的对象,它只需要一个实例,因为它没有携带任何“状态”(元素)。由于List 的类型参数是协变的,对于任意类型A,Nil 是所有List[A] 的子类型。所以,我们不需要分开Nil[A] 实例,一个实例就够了。
6、Unit
先不多说,源码在此
package scala
final abstract class Unit() extends scala.AnyVal {
override def getClass() : _root_.scala.Predef.Class[scala.Unit] = { /* compiled code */ }
}
object Unit extends scala.AnyRef with scala.AnyValCompanion {
def box(x : scala.Unit) : scala.runtime.BoxedUnit = { /* compiled code */ }
def unbox(x : java.lang.Object) : scala.Unit = { /* compiled code */ }
override def toString() : java.lang.String = { /* compiled code */ }
}
Unit是函数和方法的返回值类型,表示没有返回值。这一点和java的void有点像,但不等同于java的void,因为java的void可以返回null。