1.建立Array
// array 建立方法1
val arr = new Array[String](3)
arr(0) = "1"
arr(0) = "x"
//底层调用 def update(i: Int, x: T) { throw new Error() }
arr(1) = "1"
arr(2) = "2"
println(arr.mkString(","))
//x,1,2
// array 建立方法2
val arr2 = Array("x","y","z")
println(arr2.mkString(","))
//x,y,z
2.list
//建立列表
val oneTwo = List(1, 2)
val threeFour = List(3, 4)
//将oneTwo 中的元素所有加到threeFour 前部
val oneTwoThreeFour = oneTwo ::: threeFour
val twoThree = List(2, 3)
//:: 是右操做数twoThree 的方法
val oneTwoThree = 1 :: twoThree
//list 的经常使用方法
oneTwoThreeFour.count(_ % 2 == 0) //统计偶数的数量
oneTwoThreeFour.drop(2) //返回丢弃前两个元素的list
oneTwoThreeFour.exists(_ == 2) // 是否存在元素2
oneTwoThreeFour.filter(_ % 2 != 0) //过滤出奇数
oneTwoThreeFour.forall(_ % 2 == 0) //list中是否全是偶数
oneTwoThreeFour.head // list 第一个元素
oneTwoThreeFour.tail// 返回除第一个元素的其余元素组成的list
oneTwoThreeFour.init//除最后一个元素的list
oneTwoThreeFour.last// 最后一个元素
oneTwoThreeFour.reverse //list 反转
oneTwoThreeFour.sortWith((x, y) => x < y) //list 排序
list一经建立就不可变,里面的值也不可变
list 不提供append 方法,由于随着列表长度的增长,append 方法(会不断的建立的新数组,复制上一个列表的值进去)的操做时间呈线性增加,而 :: 方法的时间是固定的
3.元组
val tp = (1,2,"salary")
println(tp._2)
元组中能够存放不一样类型的元素,(1,2,"salary") 存放了(int,int,String)类型的值,能够用于返回不一样类型组合的返回值。
为何不用 tp(0) 这种方式取值?由于tp中的每一个元素的类型不是固定的
4.set and map
val set = Set(1, 2, 3, 5) //不能够调用 += 方法,除非将set 声明为var
val set2 = scala.collection.mutable.Set.empty[Int]
set2 += 1
set2 += 2
set2 ++= set
println(set2)
//Set(1, 5, 2, 3)
val map = Map("x" -> 1, "z" -> 2)
val map2 = scala.collection.mutable.Map.empty[String, Int]
map2 += "x" -> 1
map2 += "y" -> 2
map2 ++= map
println(map2)
//Map(z -> 2, y -> 2, x -> 1)
5.读取文件
val lines = Source.fromFile(filename).getLines().toList //若是不调用toList 方法,则返回的是 Iterator ,只能遍历一遍
val line = lines.reduceLeft((x, y) => if (x.length > y.length) x else y)
println(line)
println("=" * 30)
lines.foreach(println)
Michael, 15
==============================
Michael, 15
Andy, 30
Justin, 19
6.scala 中定义反作用方法
一般scala用以下方式定义带反作用的方法,相似java中的方法定义,这样的定义默认返回值类型是Unit,所以函数末尾虽然写了 "s" ,s也会被转化为Unit
def sideEffectFunc(s: String) {
println(s)
s
}
7.scala 的每一个源文件都隐含了对包java.lang、 包scala,以及单例对象Predef的成员的引用,PreDef 包含了许多有用的方法,例如println 语句 实际调用了 Predef 的
def
println(x: Any) = Console.
println
(x),能够看到它又调用了Console。println(x) 方法
8.App 特质,继承App 能够省去不少代码编写工做,没必要编写main类,就可直接运行
import scala.App
object Test2 extends App {
println("jaosn")
}
9.scala 对象相等性比较
scala 中 "==" 与java 中的 equal 相似,比较的是对象的内容,eq ne 比较的是对象的引用地址是否相同
"==" 比较逻辑:先看左操做数是否为null ,若不是null 则调用左操做数的 equal 方法比较,所以scala 能够省去判断是否为null
10.
scala 编译器会把类内部既不是字段也不是方法定义的代码编译
到 主 构造器中
11.scala 里每一个辅助构造器的第一个动做都是调用同类的别的构造器(包括主构造器),即都是以 this(……)开始的,也就是说每一个构造器调用终将结束于对主构造器的调用,所以主构造器是类的惟一入口
12.scala中的常量,习惯命名方式是驼峰命名法,首字母大写 好比:MaxValue
13.一个案例
class Rational(n: Int, d: Int) {
require(d > 0)
private val g = gcd(n.abs, d.abs)
val numer = n / g
val denom = d / g
def this(i: Int) = this(i, 1)
def +(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)
def -(that: Rational): Rational = new Rational(numer * that.denom - that.numer * denom, denom * that.denom)
def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)
def /(that: Rational): Rational = new Rational(numer * that.denom, denom * that.numer)
override def toString: String = {
if (denom == 1) s"$numer" else s"$numer / $denom"
}
private def gcd(a: Int, b: Int): Int = {
if (b == 0) a else gcd(b, a % b)
}
}
object Rational {
def main(args: Array[String]): Unit = {
//隐式转换,解释器会自动将int 类型转换为Rational
implicit def intToRational(i: Int): Rational = {
new Rational(i)
}
val r = new Rational(2, 3)
println(4 + r)
println(r + 4)
}
}
14.scala 中的赋值语句返回值为 Unit ,所以 while ((line = in.readLine())!= "") 永远返回true
15.带过滤器的for
for (i <- 1 to 10 if i % 2 == 0; if i != 4) {
println(i)
}
16.for嵌套循环
for (i <- 1 to 9 ;j <- 1 to i) {
print(s" $j * $i = ${i*j} ")
if(i==j) println()
}
17.yield 表达式
val seq = for (i <- 1 to 10) yield {
val j = if (i % 2 == 0) i * 2 else i * 3
i * j
}
18.try catch 捕获异常
try{
val file = new File("aa")
}catch {
case ex:FileNotFoundException => println("aa not exists")
case ex => ex.printStackTrace()
}
19.带返回值的try catch
def getUrl(url: String) = try {
new URL(url)
} catch {
case ex => new URL("www.baidu.com")
}
20.重复参数
def echo(args: String*): Unit = {
args.foreach(println)
}
能够将方法的最后一个参数定义为重复参数,方法是再类型后加 * ,实际上atgs* 类型是 Array[String],可是传参的时候却不能传 数组 ,好比:val arr = Array("a","b");echo(arr),此时会报错,正确的写法是 echo(arr:_*)
21.scala.util.Try
def testTry(): Unit ={
val tt = Try(24/2)
tt match {
case Success(a) => println(a)
case Failure(a) => a.printStackTrace()
}
}
22.抽象类
abstract class Element {
def contents: Array[String]
}
抽象类class 关键字前必须带有
abstract ,不带 = 和方法体的方法即为抽象方法,抽象方法不用带
abstract
23.访问字段值比调用方法略快,由于字段值在类初始化时就已经预先计算,而方法在每次调用时都要计算,可是字段值占用的空间略大
24.scala 建议将没有参数且不带反作用的方法定义成无参数方法风格(不带括号的方法),将不带参数可是有反作用的方法定义成空括号方法。千万不要将不带参数且有反作用的方法定义成无参数方法风格,午饭方法的访问相似访问属性,客户会奇怪,为何这个属性具备反作用
25.继承
class ArrayElements(conts: Array[String]) extends Element {
override def contents: Array[String] = conts
}
继承表示超类的全部的成员都属于子类,如下两种状况除外,1.超类的私有成员,2.被子类重写的超类成员
scala 中若是超类的成员是具体,非抽象的,子类重写该成员时必须加override 关键词,若是是抽象的,则可加可不加
26.若是属性或方法不但愿子类重写,则能够加final 关键字,如
final def height: Int = contents.length
27.scala 继承建议:将子类写在抽象类的伴生对象中,并定义为private,抽象类伴生对象中定义建立子类的工厂方法
28.scala 的根类是Any
Any 有两个子类:AnyVal 和AnyRef,AnyVal 是每一个内建值类的父类,有9个这样的值类,Byte,Short,Char,Int,Long,Float,Double,Boolean,Unit,前八个对应了java的八个基本类型,运行时会转换成java的八大基本类型,他们不能用new I建立,由于他们时abstract 且是final的
第九个 是 Unit,至关因而java中的void,它的值是 “()”,
AnyRef 是全部引用类的基类
28.scala.Null 是null引用对象的类型,它是每一个引用类(继承自AnyRef)的子类,null 不兼容值类型。Nothing 位于scala 层级的最底层,是任何其余类型的子类型,Nothing类型没有任何值,Nothing 一般用于不正常的终止,好比error
29.trait的使用,除了如下两点外,与类的使用无别
1)特质不能有“类”参数, 好比 trait Foo(i:Int){} ,编译会报错
2)在类中super 调用是静态绑定的,而在trait中super 的调用是动态绑定的,在定义特质的时候,super调用方法的实现还没有被定义
30.
Ordered 特质
在开发中咱们常常要用到比较,比较无非 <,> ,<= ,>=无论哪一个类,这四种比较的逻辑都不会改变,scala 提供了Ordered特质来帮助类实现比较,咱们惟一要作的就是混入 Ordered[C] 特质(C 是要比较的类),让后实现compare 方法,this < that 则返回 <0 的值,相等返回 0,
31.特质的堆叠使用
package com.program
import scala.collection.mutable.ArrayBuffer
abstract class IntQueue {
def get: Int
def put(i: Int)
def hasNext: Boolean
}
class BasicIntQueue extends IntQueue {
private val queue = new ArrayBuffer[Int]()
override def get: Int = queue.remove(0)
override def put(i: Int): Unit = {
println(s"i 的值是:$i")
queue += i
println(s"值添加完毕")
}
override def hasNext: Boolean = {
queue.size > 0
}
}
trait Doubling extends IntQueue {
abstract override def put(i: Int): Unit = {
println(s"double 前 ")
super.put(i * 2)
println(s"double 后 ")
}
}
trait Incement extends IntQueue {
abstract override def put(i: Int): Unit = {
println(s"increment 前 ")
super.put(i + 1)
println(s"increment 后 ")
}
}
trait Filter extends IntQueue {
abstract override def put(i: Int): Unit = {
println(s"filter 前")
if (i > 0) super.put(i)
println(s"filter 后")
}
}
class Foo1 {
def foo(): Unit = {
println("foo1")
}
}
class Foo2 extends Foo1 {
override def foo(): Unit = {
println("foo2 前")
super.foo()
println("foo2 后")
}
}
class Foo3 extends Foo2 {
override def foo(): Unit = {
println("foo3 前")
super.foo()
println("foo3 后")
}
}
object Test2 extends App {
val myqueue = new BasicIntQueue with Doubling with Incement with Filter
myqueue.put(1)
myqueue.put(1)
myqueue.put(2)
while (myqueue.hasNext) {
println(myqueue.get)
}
println("=" * 20)
val foo = new Foo3
foo.foo()
}
filter 前
increment 前
double 前
i 的值是:4
值添加完毕
double 后
increment 后
filter 后
filter 前
increment 前
double 前
i 的值是:4
值添加完毕
double 后
increment 后
filter 后
filter 前
increment 前
double 前
i 的值是:6
值添加完毕
double 后
increment 后
filter 后
4
4
6
====================
foo3 前
foo2 前
foo1
foo2 后
foo3 后
由输出结果可知特质的堆叠是从最右侧的特质开始的
32.样本类
case class Foo(i:Int)
scala 编译器会自动为样例类添加一些便捷设定:
1)自动添加与类名一致的工厂方法,因此能够用 Foo(1) 来建立Foo 对象
2)样例类的参数列表里的参数隐式添加了 val,这些参数会做为样例类的属性存在
3)编译器为样例类添加了 toString,hashCode和equal 的“天然”实现
33.封闭类
一旦你写了模式匹配,就得保证考虑到了全部可能的状况,不然程序就会报错,scala 提供了一种检查机制,能够将超类封闭起来,这样在编译时scala 会自动检查全部的匹配可能,可是,你必须把全部子类定义在存放超类的文件中,并在超类前加上 sealed,以下
package com.program
sealed abstract class Animal
case class Fish(sound:String) extends Animal
case class Bird(sound:String) extends Animal
case class Horse(sound:String) extends Animal
object Sealtest {
def main(args: Array[String]): Unit = {
val animal:Animal = Fish("gulu")
val sound = animal match {
case Fish(x) => x
}
}
}
如上代码编译时会有以下提示:
Warning:(10, 17) match may not be exhaustive.
It would fail on the following inputs: Bird(_), Horse(_)
val sound = animal match {
若是不但愿编译器进行检查,能够加上(animal:@unchecked)match ,实测很差用,scala 没法识别(sclaal 版本2.11.8)
val list = List(1, 2, 3)
list match {
case e@List(_*) => println(e) //List(1, 2, 3) 能把e所表明的变量取到
}
34.list 类
package com.program
object ListSuite {
//插入排序,xs 已是排序的
def insert(x: Int, xs: List[Int]): List[Int] = {
if (xs == Nil || x < xs.head) {
x :: xs
} else {
xs.head :: insert(x, xs.tail)
}
}
//对list 排序,list 的元素是无序的
def isort(xs: List[Int]): List[Int] = xs match {
case Nil => Nil
case head :: tail => insert(head, isort(tail))
}
def main(args: Array[String]): Unit = {
//插入排序
var list = List(2)
list = insert(1, list)
list = insert(3, list)
list = insert(4, list)
list = insert(5, list)
println(list) //List(1, 2, 3, 4, 5)
//插入排序
//随机列表排序
val list2 = List(3, 4, 1, 2, 6)
println(isort(list2)) //List(1, 2, 3, 4, 6)
//随机列表排序
//列表模式
val listFruit = List("apple", "banana", "orange")
val List(apple, banana, orange) = listFruit
println(apple) // apple
val x :: rest = listFruit
println(x) // apple
//列表模式
//llist 一阶方法
//列表拼接
val listconcat = list ::: list2 //List(1, 2, 3, 4, 5, 3, 4, 1, 2, 6)
//获取列表的长度,会遍历列表的每个元素,耗时,若是只需得知列表是否为空,能够调用listconcat.isEmpty
listconcat.length
//列表反转
println(list.reverse) //List(5, 4, 3, 2, 1)
println(list.take(2)) //List(1, 2)
println(list.drop(2)) //List(3, 4, 5)
println(list.splitAt(2)) //(List(1, 2),List(3, 4, 5))
println(list(2)) //获取list 的index 为2的元素,等价于 list.drop(2).head,因此比较耗时
println(list.indices) //Range(0, 1, 2, 3, 4) 索引值组成的列表
println(list.zip(list2)) //List((1,3), (2,4), (3,1), (4,2), (5,6))
println(list.zipAll(9 :: list2, 2, 3)) //List((1,9), (2,3), (3,4), (4,1), (5,2), (2,6))
println((list.zip(list2)).unzip) //(List(1, 2, 3, 4, 5),List(3, 4, 1, 2, 6))
println(list.partition(_ % 2 == 0)) //(List(2, 4),List(1, 3, 5))
println(list.find(_ % 2 != 0)) //返回第一个知足条件的元素
println(list.takeWhile(_ % 2 != 0)) //List(1) 返回知足条件的最长序列
println(list.dropWhile(_ % 2 != 0)) // List(2, 3, 4, 5)
println(list.span(_ % 2 != 0)) // (List(1),List(2, 3, 4, 5)) takeWhile and dropWhile 的组合
println(list.exists(_ % 2 == 0)) //true
println(list.forall(_ % 2 != 0)) //false
val max = (0 /: list) ((x, y) => if (x > y) x else y)
println(max) //5
val min = (list :\ 0) ((x, y) => if (x < y) x else y)
println(min) //0
println(List.fill(5)("a")) //List(a, a, a, a, a)
}
}
35.泛型,上界,下界,协变,逆变
37 若是想在列表尾部追加元素,可使用高效的listBuffer,使用listBuffer 还能够避免堆栈溢出
val lb = new ListBuffer[Int]
lb += 1
lb += 2
println(lb) //ListBuffer(1, 2)
38.若是须要可变长的数组,可使用ArrayBuffer,除了与array相同的操做外,还增长了首位添加,删除操做
val ab = new ArrayBuffer[Int](10)
ab += 1
ab += 2
ab.remove(0) // 1 有返回值
39.若是须要先进先出的序列,可使用queue,queue分为两种,一种是可变队列,一种是不可变队列
val que = Queue(0) 不可变
val que2 = que.enqueue(1)
val que3 = que2.enqueue(List(2,3,4))
println(que3) //Queue(0, 1, 2, 3, 4)
println(que3.dequeue) //(0,Queue(1, 2, 3, 4))
val mque = collection.mutable.Queue(0)
mque += 1
mque += 2
println(mque) //Queue(0, 1, 2)
println(mque.dequeue()) //0
40.若须要先进后出的序列,可使用stack,stack 也有可变和不可变的
val stack = collection.mutable.Stack(0)
stack.push(1)
stack.push(2)
println(stack) //Stack(2, 1, 0)
println(stack.top)//2
println(stack.pop())//2
println(stack)//Stack(1, 0)
41.set 基本操做
var set = Set(1,2)
set += 5
set -= 1
set ++= List(3,4,5)
set --= List(2,3)
println(set)
println(set.intersect(Set(5,6))) //交集
42.map的基本操做
val map = collection.mutable.Map.empty[String, Int]
map += "a" -> 2
map += "a" -> 2
map += "a" -> 2
map("b") = 3
map ++= List("c" -> 3, "d" -> 4)
map --= List("a", "b")
println(map.keys) //iterator
println(map.values) //iterator
println(map.keySet) //set
println(map)
可变map 和不可变map的相互转换
scala.collection.mutable.HashMap.empty[Int, Int] ++ Map(1 -> 1)
Map.empty[Int, Int] ++ collection.mutable.HashMap(1 -> 1)
43.默认的集和映射
scala.collection.mutable.Set 工厂方法默认返回:
scala.collection.mutable.HashSet
scala.collection.mutable.Map 工厂方法默认返回:
scala.collection.mutable.HashMap
不可变集合的工厂方法返回对象比较复杂;
set
map
44.将类的主构造器设置为私有的
将没法经过主构造器建立实例,可是若是有辅助构造器,依然可使用辅助构造器建立实例
class Queue[T]
private
(val lead: List[T], val tail: List[T])
45.信息隐藏,不向用户暴漏代码实现细节
方案一:
class Foo private(val a:Int,val b:Int)
object Foo{
def apply(a:Int,b:Int) = new Foo(a,b)
}
方案二:
trait Foo{
val a:Int
val b:Int
}
object Foo{
def apply(...) = new FooSub(...)
private class FooSub extends Foo{
....
}
}
推荐使用方法二
46.为何要用type
理由之一:提供一个类型的别名,能够避免冗长的类型名字
47.一个例子
package com.program
class AbstractTest() extends Ft {
val a = 3
}
trait Ft {
val a: Int
require(a > 0)
}
object AbstractTest {
def main(args: Array[String]): Unit = {
println(new AbstractTest().a)
}
}
Exception in thread "main" java.lang.IllegalArgumentException: requirement failed
at scala.Predef$.require(Predef.scala:212)
at com.program.Ft$class.$init$(AbstractTest.scala:10)
at com.program.AbstractTest.<init>(AbstractTest.scala:3)
at com.program.AbstractTest$.main(AbstractTest.scala:15)
at com.program.AbstractTest.main(AbstractTest.scala)
运行为什么回报错,由于
AbstractTest 在初始化以前,先要初始化父类,此时val a 还未被初始化,因此报错
改为下面的写法就能够了
class AbstractTest(val a: Int) extends Ft {
}
48.枚举简单使用
package com.program
object WeekDay extends Enumeration {
type WeekDay = Value
val Mon = Value("1")
val Tue = Value("2")
val Wed = Value("3")
val THu = Value("4")
val Fri = Value("5")
val Sat = Value("6")
val Sun = Value("7")
def checkExists(day: String): Boolean = {
this.values.exists(_.toString == day)
}
def isWorkDay(day: WeekDay): Boolean = {
!(day == Sat || day == Sun)
}
def showAll = this.values.foreach(println)
}
object EnumTest {
def main(args: Array[String]): Unit = {
println(WeekDay.checkExists("8"))
println(WeekDay.Sun == WeekDay.withName("7"))
println(WeekDay.Sun == 7)
WeekDay.showAll
println(WeekDay.isWorkDay(WeekDay.Sat))
}
}
49.scala and xml
package com.program
import scala.xml.dtd.DocType
object XMLTest {
def main(args: Array[String]): Unit = {
//xml 字面量
val hw = <a>
{"hello" + ", world"}
</a>
println(hw)
val num = 100 //<a>hello, world</a>
val node = <a>{if (num > 100) <num>{num}</num> else xml.NodeSeq.Empty}</a>
println(node) //<a></a>
//推荐使用xml字面量,请看下面两个例子
println(<a>
{"</a>可能存在危险"}
</a>)
//若使用低级字符串,则容易形成相似sql注入的结果
println("<a>" + "</a>可能存在危险" + "</a>")
//xml 序列化
val stu = new Student {
override val name: String = "jason"
override val tel: String = "1345"
override val addr: String = "sh"
override val age: Int = 27
}
val stuXml = stu.toXml
println(stuXml)
/*<student>
<name>jason</name>
<age>27</age>
<addr>sh</addr>
<tel>1345</tel>
</student>*/
//若是想在xml文本中包含 {} 则能够用{} 转义
val x = 23
println(<a>{{{x}}}</a>) //<a>{23}</a>
//xml 拆解
val n3 = <a namea="na">a<b nameb="nb">b<c>c</c></b></a>
println(n3.text) //abc
println(n3 \ "b") //<b>b<c>c</c></b>
println((n3 \ "b").text) //bc
println(n3 \ "c") // "" 空字符串
println(n3 \\ "c") //<c>c</c> 两个斜杠表明深度搜索
println(n3 \\ "@nameb") // nb 获取标签的属性
//xml 反序列化
val stu2 = stu.fromXml(stuXml)
println(stu2)
//xml 的存储与加载
xml.XML.save("stu.xml", stuXml, "utf-8", true, null)
xml.XML.loadFile("stu.xml")
//xml 与模式匹配
def proc(node: xml.Node): String = node match {
case <a>{contents}</a> => s"it is an a : ${contents}"
case <b>{contents}</b> => s"it is a b : ${contents}"
case _ => s"it is something else"
}
println(proc(<a>apple</a>)) //it is an a : apple
//proc 目前只能进行单个子节点的匹配 ,若是要匹配出如下内容,能够用proc2方法
println(proc(<b>a<em>yellow</em>banana</b>))//it is something else
println(proc(<o>orange</o>))//it is something else
def proc2(node:xml.Node):String = node match {
case <b>{contents @ _*}</b> => s"it is b ${contents}"
case _ => s"it is something else"
}
println(proc2(<b>a<em>yellow</em>banana</b>))//it is b ArrayBuffer(a, <em>yellow</em>, banana)
//模式匹配与for
val n4 =
<students>
<student>
<name>jason</name>
<age>25</age>
<addr>sh</addr>
<tel>123</tel>
</student>
</students>
println("=================")
n4 match {
case <students>{students @_*}</students> =>
for(student <- students){
println((student \ "name").text)
}
case _ => println("nothing")
}
println("=================")
/*=================
jason
=================*/
println("<<<<<<<<<<>>>>>>>>>")
n4 match {
case <students>{students @_*}</students> =>
for(student @ <student>{_*}</student> <- students){
println((student \ "name").text)
}
case _ => println("nothing")
}
println("<<<<<<<<<<>>>>>>>>>")
//<student>{_*}</student> 限制了for 表达式的枚举
/*<<<<<<<<<<>>>>>>>>>
jason
<<<<<<<<<<>>>>>>>>>*/
}
}
abstract class Student {
val name: String
val age: Int
val addr: String
val tel: String
def toXml =
<student>
<name>{name}</name>
<age>{age}</age>
<addr>{addr}</addr>
<tel>{tel}</tel>
</student>
def fromXml(node: xml.Node): Student = {
new Student {
override val name: String = (node \ "name").text.trim
override val tel: String = (node \ "tel").text.trim
override val addr: String = (node \ "addr").text.trim
override val age: Int = (node \ "age").text.trim.toInt
}
}
override def toString = s"Student($name, $age, $addr, $tel)"
}
50.scala 中的equals 方法,最好与hashcode 一块儿重写
class Foo11(final val x: Int, final val y: Int) {
override def hashCode(): Int = Objects.hash(new Integer(x), new Integer(y))
override def equals(obj: scala.Any): Boolean = obj match {
case that: Foo11 => (that canEqual (this)) && that.x == this.x && that.y == this.y
case other => false
}
def canEqual(other: Any): Boolean = other.isInstanceOf[Foo11]
}
class Goo11(x: Int, y: Int, val z: Int) extends Foo11(x, y) {
override def hashCode(): Int = super.hashCode() + Objects.hash(new Integer(z))
override def equals(obj: Any): Boolean = obj match {
case that: Goo11 => (that canEqual this) && super.equals(that) && that.z == that.z
case other => false
}
override def canEqual(other: Any): Boolean = other.isInstanceOf[Goo11]
}
51.akka
52.Option 的一些用法
val mapx = Map("name" -> "jason", "age" -> "?")
val s: String = null
val a = Option(s).orElse(mapx.get("name")).orNull
println(a) //jason
println(Option("TOM").map(_.toLowerCase)) //Some(tom)