1. scala的数学操作符实际上是方法,如a+b等于a.+(b)
2. /%是BigInt的一个方法,也就是说,scala的方法名可以用任意字符
3. scala不用强制类型转换,而用方法,比如val r=99.4.toInt
4. scala没有也不需要包装类型 / scala没有基本类型和包装类型之分,如你创建的Int数组在虚拟机 中就是int[]数组,不像java那样还有Integer[]数组
5. scala的RichInt、RichDouble、RichChar等提供了基本类型不具备的方法,如1.to(10)中的to就是RichInt的方法,它先将Int值1转换为RichInt,再应用to方法
6. 1.to(10)等价于1 to 10,类似上面的a.+(b)等价于a+b
7. scala没有++和-- 操作符,这一点和python一样,和java、C++不一样
8. StringOps是对String的包裹,例如"hello".intersect("world")输出"lo",其中"hello"被隐式转换成一个StringOps对象,然后intersect方法被调用(引申:intersect方法实际上来自SeqLike特质,而StringOps和SeqLike的关系链是,StringOps类-->StringLike特质-->IndexedSeqOptimized特质-->IndexedSeqLike特质-->SeqLike特质,其中-->表示继承或混入,比较复杂)
9. scala没有静态方法,但有单例对象(也叫伴生对象),能提供类似静态方法的方法,比如BigInt伴生对象的apply方法,当BigInt("123456")就等于调用了BigInt.apply("123456"),不需要new!!
10. 不带参数的scala方法通常不用圆括号,如"hello".distinct
11. "hello"(4)背后是apply方法,即"hello".apply(4); 而Array(1,4,9,16)背后也是Array的apply方法
12. 标识为implicit的方法为自动隐式转换
13. 方法可以函数作为参数,如s.count(_.isUpper)
14. String和Int的公共超类是Any,事实上是因为,String的超类是AnyRef,而Int的超类是AnyVal,而AnyRef和AnyVal的超类是Any
15. if表达式的两个分支可以是不同的数据类型,如if (x>0) "positive" else 0,注意,该表达式的返回类型为Any,因为String和Int的公共超类是Any
16. if表达式可以省略else分支,如if (x>0) 1
17. 为了避免if没有输出值,系统会用Unit,写作(),因此省略else等价于if (x>0) 1 else ()
18. scala的Unit类似java的void,但区别是void没有值,而Unit有无值的值,即()
19. scala没有switch,但有强大的模式匹配,即match case表达式
20. REPL是短视的,一次只能看一行,如果想表达if和else if的逻辑整体,需要用花括号连接
21. REPL的:paste可以复制整块代码
22. 不要串联赋值,如x=y=1,因为y=1的值为Unit了
23. scala的打印函数有print、println和printf,其中printf和C语言的类似,均来自scala.Predef
24. scala的读取函数有readLine、readInt、readChar、readByte等,来自scala.io.StdIn包
25. scala的while和do,与java一样,但for不一样,功能更强大,常用的for用法如下,for(i<-0 until s.length) 或for(i<-1 to n)或for(ch<-"hello"),其中要注意until和to的区别。另外还有for yield的用法
26. scala没有break和continue,但有Breaks对象,其中有break方法,可以达到跳出的效果,原理是通过抛出异常(throw breakException),需要import scala.util.control.Breaks._
27. for循环高级用法,即生成器,可以带一个守卫,还可以任意引入变量
28. scala的函数,只要不是递归,可以不指定返回类型
29. 函数中一般不用return,但可以把return当做函数版的break
30. scala也有变长参数,如args:Int*,假如定义了sum(args:Int*)方法,就可以val s=sum(1 to 5: _*),这里将1 to 5当做参数序列处理,其中追加_*用来转换成参数序列
31. 没有返回值的函数叫做过程,也可以将过程的返回值设为Unit,但是要加=
32. val被声明为lazy时,表示惰性求值,初始化将被推迟
33. Int和AnyRef的类型转换,比如42.asInstanceOf[AnyRef]为啥能转成功,是因为Int的伴生对象有一个box方法,它将Int转为java.lang.Integer,而Integer是引用类型,即AnyRef
34. scala的异常和java一样,也是throw Exception,也必须是java.lang.Throwable的子类。但是,scala没有受检异常,即不需要声明函数会抛出某种异常
35. throw表达式的类型是Nothing
36. if else表达式的类型是throw表达式之外另一个分支的类型
37. 捕捉异常采用模式匹配,而通常异常在具体异常之后。如果不需要异常对象,用_即可
38. 定长数组用Array,注意,定长是长度不变,元素值是可以变的
39. jvm中,scala的Array以java数组方式实现,即Array(1,2,3)就是一个int[]
40. ArrayBuffer等价于java的ArrayList,以及C++的vector,它的路径是scala.collection.mutable.ArrayBuffer
41. 假如b是ArrayBuffer,可以执行b+=1、b+=(1,2,3)、b++=Array(8,13,21)、b.trimEnd(5)等。除了尾部,也可以在任意位置插入或移除元素,如b.remove(1),以及b.insert(2,9),但不高效,因为后面元素都会被平移
42. 假设b是ArrayBuffer,那么var a=b.toArray,和a.toBuffer可以互相转换
43. until是RichInt的方法,返回小于但不包括上限的所有值。0 until 10其实是0.until(10);而0 until (a.length,2)表示每两个元素一跳;(0 until a.length).reverse表示从尾端开始遍历
44. filter和map可以代替for守卫和yield,因为更加函数化编程
45. Array和ArrayBuffer有sum、max、min、sorted、count、copyToArray、contains等操作
46. b.sortWith(_ < _)表示升序,b.sortWith(_ > _)表示降序;另一种方法,b.sorted是升序,而b.sorted.reverse表示降序
47. 可以对Array排序,但不能对ArrayBuffer排序。注意:sortWith和sorted都不能对原Array/ArrayBuffer排序,而是拷贝出来的。要想真正对Array原地排序,可以使用Sorting单例对象提供的quickSort方法,例如scala.util.Sorting.quickSort(a)
48. a.mkString("and")用于指定分隔符,或者如a.mkString("<",",",">")
49. ArrayOps为Array提供了一些操作,如toArray、slice、flatten等,注释中有几句话可以描述二者的关系:This class serves as a wrapper for `Array`s with all the operations found in indexed sequences. Where needed, instances of arrays are implicitly converted into this class. 以及The conversion to `ArrayOps` is temporary, as all operations defined on `ArrayOps` return an `Array`
50. TraversableOnce特质是scala集合中最常用的一个,其他通用特质还有Traversable和Seq等
51. B>:A表示B是A的超类,如Any是Int的超类
52. Array.ofDim[Double](3,4)来构造二维数组,三行四列,初始化为全0; 访问使用两对圆括号,如matrix(row)(col)=42;需要注意:scala的多维数组,同一维度,数组长度可以不同,比如new Array[Array[Int]](10)之后,对每一数组可以设置不同的长度
53. scala.collection.JavaConverters提供了隐式转换方法,如bufferAsJavaList、asJavaCollection、asScalaBuffer等
54. scala的Map也叫映射,默认是scala.collection.immutable.Map,其值是不可变的。可变映射是scala.collection.mutable.Map,当然还有scala.collection.mutable.HashMap
55. 可以使用->或圆括号来创建Map的内容。注意:映射和函数在调用上都是用(),因此非常相似
56. Map有contains、getOrElse、keySet、values等方法。Map.get返回的是Option对象,要么是Some(键对应的值),要么是None
57. 可以用+=为Map添加多个元素,当然也可以用-=来移除某个key对应的元素
58. immutable.SortedMap是不可变的树形映射(key有序);mutable.SortedMap是可变的树形映射(key有序),可以用java的TreeMap来代替
59. mutable.LinkedHashMap是可变的映射,且按照插入顺序访问
60. scala.collection.JavaConverters还提供了mapAsScalaMap、mapAsJavaMap、propertiesAsScalaMap等方法
61. scala的元组和python一样,可以同时包含不同类型的元素,如(1, "s")
62. scala预定义的元组有22个,从Tuple1到Tuple22,如Tuple3表示3个元素的元组,用_1 _2 _3来访问元素。注意,Tuple3样例类和Product3特质的关系。另外,t._2可以写为t _2,但不能写为t_2,即空格不能少
63. StringOps有一个partition方法,返回一对字符串,分别包含满足和不满足某条件的字符,如"hello WORLD".partition(_.isUpper),得到(String, String) = (WORLD,"hello ")
64. 和python一样,scala也有zip,即拉链操作
65. 两个Array的元素对应,可以用zip得到对偶的集合,然后用toMap变为映射,比如keys.zip(values).toMap
66. scala的类自带getter和setter;而@BeanProperty用于生成getter和setter
67. scala的类有主构造器(只有一个)和辅助构造器(可以有任意多个),后者的名称固定为this,这点和java、C++不同
68. scala的类默认都是public,因此可以省略;一个文件可以有多个public类
69. 私有字段配合getter和setter(都是public)比直接用公共字段好。私有字段的默认getter和setter也是私有的
70. 事实上scala的getter和setter并非被命名为getXxx和setXxx,而是类似age、age_=这种形式,可通过javap查看。可以重新自定义实现getter和setter,比如使age不能变更年轻
71. 如果字段是val,那么只有getter方法被生成。如果不需要getter和setter,那么只需要将字段声明为private[this]
72. 属性加private[this]将不能通过对象.value的形式访问,这叫做对象私有。注意:类私有会生成getter和setter,而对象私有不会生成
73. private[类名]将访问权赋予指定的类,可以是该类或包含该类的外部类
74. 辅助构造器必须以对其他已定义的其他辅助构造器或主构造器的调用开始
75. 主构造器不以this方式定义,而是和类交织在一起,具体就是主构造器参数直接放在类名之后,参数会被编译为字段
76. 与java不同,scala的类定义可以直接写语句,比如println,而不必写在方法中
77. 主构造器使用默认参数可以避免过多的使用辅助构造器
78. 主构造器的参数可以不带val或var,如果不带这两个的参数至少被一个方法使用,那么它将被升格为字段。以上字段等同于private[this] val字段
79. class Person private(val id:Int)使得主构造器变为私有,那么只能通过辅助构造器来构造Person对象
80. scala有各种嵌套,比如函数中可以有函数,类中可以有类,特质中可以有特质
81. 和java不同,在java中内部类从属于外部类,而scala中,a.Member和b.Member是不同的类,假如a和b是外部类的不同实例,而Member是内部类,即每个实例可以有自己的内部类
82. Network#Member是类型投影,表示任何Network的Member
83. 在内部类中,可以使用外部类.this来访问外部类的引用。还可以使用外部类的别名,比如outer=>,使的outer指向外部类. this。可以用任何别名,但最好不要用self,会导致歧义
84. 类和它的伴生对象可以互相访问私有特性,且必须存在于同一个源文件中。类的伴生对象可以被访问,但不属于作用域,所以要加"类名.方法"
85. scala也有abstract class和extends,且object可以extends class或extends trait,当一个object扩展了一个或多个trait,结果就是一个扩展了指定类以及特质的类的对象
86. 与java的@Override注解类似但不同,scala提供了override关键字用于重写,可以置于方法或字段前面,如override val repr: String 或override def toString=repr
87. Object(参数1,参数2..)会调用apply方法,返回的是伴生类的对象 。注意:伴生对象必须要定义apply方法,且返回伴生类的对象
88. Array(100)和new Array(100)区别是,前者调用了apply(100),输出一个单元素的Array[Int],值为100,而后者调用的是this(100)生成一个Array[Nothing],包含100个null元素
89. App特质扩展了DelayedInit特质。较老的Application特质没有优化,因此推荐用App特质
90. scala没有枚举,但提供了Enumeration助手类,可用于产生枚举。枚举如果不指定参数,将默认从0开始,并且在前一个枚举基础上加一。引用枚举可以用"类名.枚举名",枚举的Id可以用". id" 来返回,名称用". toString"返回,如Color(0)可以和Color.withName("red")等价
91. scala的package可以嵌套,且同一个包可以定义在多个文件中。包的作用域规则,下层可以访问上层。scala的包更灵活,比java更容易冲突,java中包名总是绝对的,scala的包名是相对的
92. 解决包名冲突的方法是,使用绝对包名,以_root_开始,比如_root_.scala.collection.mutable. ArrayBuffer;还有一种方法避免冲突,那就是使用串联式包语句,比如package com.xxx.yy{...},即在定义包的时候,把包名的路径区段写出来
93. 包除了嵌套标记法,也可以使用传统的顶部标记法
94. 包可以包含类、对象和特质,但不能包含变量和函数,这是jvm决定的
95. 每个包有一个包对象,即package object,名称与包一样,比如package object people和package people
96. 包对象会被编译为带静态方法和字段的jvm类,即package.class
97. 可以通过加private[xx]的方式来改变方法对包的可见性,其中xx是包的某一层名称
98. 在java中*是通配符,而scala中是合法的标识符,所以尽量避免以它为名称
99. scala有选取器,即import java.awt.{Color,Font},并且支持重命名,如import java.util. {HashMap=>JavaHashMap};选取器还支持隐藏,如import java.util.{HashMap=> _,_},思考这种语法是否有副作用(注意:和python一样,scala也可以在任意位置import)
100. scala隐式引入的包有scala._,就是说,scala.StringBuilder会覆盖java.lang.StringBuilder,而不是冲突;Predef._也会被隐式引入