第一章 可伸展的语言
一、scala新增的特性:
1、增加了新的类型:在scala中增加了一个新的数据类型:BigInt (代表了如:大十进制数、复数、在理数、置信区间、多项式等这些类型)
scala允许用户通过定义感觉像原生语言支持一样的易用库在他们需要的方向上发展和改造语言。
eg:def factorial(x: BigInt): BigInt=if(x==0) 1 else x * factorial(x-1)
2、增加了新的控制结构
二、scala具有可扩展性的原因:scala语言是面向对象和函数式的溶合。
1、scala是面向对象的:java虽然也是面向对象的开发语言,但是在java中也有一些非对象值的存在,比如java中的一些初始值或者是一些不隶属于任何对象的静态字段和方法。而scala则是纯粹的面对对象语言,在scala中每一个值都是对象,每一个操作都是方法调用。如:1+2 在scala中是实际是调用了定义在Int类里面的"+"方法。
2、scala是函数式的
三、scala的特点:
1、scala是兼容的:scala兼容了java的所有特性,与java实施无缝的互操作。所有的scala程序都会被编译成JVM字节码。在scala中可以调用java的方法,访问java的字段,继承java类和实现java接口。
2、scala是简洁的:scala程序可以减少程序的代码量。原因之一:scala的方法避免了一些束缚java程序的固定写法。(在java中分号是必需的,而在scala里的分号是可选择的,通常是不写的。还就是类用构造函数的书写也能scala语言减少不少的代码)
eg:java中的类定义用构造函数
class MyClass
{
private int index;
private String name;
public void MyClass(int index, String
name)
{
this.index = index;
this.name = name;
}
}
scala对应的:
classMyClass(index: Int, name:String)
原因之二:scala的类型推断
3、scala 是高级的:scala可以通过帮助提升接口的抽象级别来帮助管理复杂性。
Eg: //在java中想知道一个String类型变量name否包含有大写字符的定法
boolean nameHasUpperCase=false;
for(inti=0;i<name.length;i++){
if(Character.isUpperCase(name.charAt(i))){
nameHasUpperCase=true;
break;
}
}
//在scala中对应的功能写法
val nameHasUpperCase=name.exists(_.isUpperCase)
4、scala是静态类型的:使用静态类型的优点在于
可检验的属性:静态类型系统可以做消除某些进的错误(如:布尔型不会与整数型相加,私有变量不会从类的的外部被访问,用正确数量的参数调用了函数,字符串集只能加入字符串)
安全的重构:静态类型系统让你可以非常有信心去变动代码基础的安全网。
文档:静态类型是被编译器检查过正确性的程序文档。
第二、三章 Scala入门
一、scala解释器
1、安装scala解释器的方法很简单,只需要从网上下载到scala相对应的包,配置好环境变量,就可以在命令提示符里输入:scala-->输入执行的语句
二、变量定义
在scala中有两种变量:
val:类似于java中的final变量,一旦初始化了,就不能再赋值。
var:如同java中的非final变量,其可以被赋值多次。
在scala语言中,变量的定义可以省略类型,scala可以通过推断来得到相应的类型;也可以加上类型,不过scala的类型变量是在变量名后面,类型与变量名是以“:”隔开的,这与java 是不同的。
三、函数定义
Scala的函数是以“def”开头的,然后是函数名
Eg:def max(x : Int , y: Int)={
if(x >y) x else y
}
如果一个函数没有返回值,则可以不用写“:[返回值类型] =”这一部分。函数默认会返回Uint类型,这类似于java中的void。
四、编写scala脚本
scala不光可以帮助程序员建造大型系统,同样适用于制造小型的脚本。
五、用while做循环,用if做判断
在scala中没有提供break和continue语句退出循环
Scala中退出循环有三种方法可以选择:
1、使用Boolean类型控制变量
2、使用嵌套循环,在内循环中return
3、使用Breaks类中的break方法(Breaks.break())
scala中没有java中的“i++”、“++i”、“i--”、“--i”这种写法
Java中while语句的用法:
int x=0;
while(x>10){
System.out.println(x);
if(x==5){
break;//continue;
}
x++;
}
Scala中while语句的用法:
var y=0
while(y>10){
println(y)
if(y==5){
return
}
y+=1
}
六、用foreach和for做枚举
Eg:
arg.foreach(a=>println(a))
for(i <- 0 to 3){
println(i)
}
结果为:
0
1
2
3
=>函数文本(相当于对象) <= 小于等于 <- for迭代 -> map 中的key value
七、使用类型参数化数组(Array)是可变的
Scala中作用new实例化对象,在实例化的过程中可以使用值和类型使对象参数化(创建实例的同时完成对其的“设置”)
在scala中访问数组是用“()”而在java中则用“[]”。这是因为scala把任何类型都当成对象,任何操作都是对象的方法调用。
八、使用列表(List)
List创建了则是不可改变的,且包含的元素类型都一样(可以不一样)。但是在scala中可以使用方法“:::”将两个或是更多的List叠加起来。使用方法“::”可以将新元素组合到现有列表的最前端。
List常用的方法
创建方法 | 说明 |
List()或Nil val list=List() val list2=Nil | 创建一个空列表 |
val thrill=”aa”::”bb”::Nil | 创建一个带有aa、bb元素列表 |
val thrill2=List(“a”,”b”):::List(“c”,”d”) | 叠加两个列表得到一个新的列表 |
访问元素的方法(类似于java中数组的访问) | 说明 |
thrill(1) | 返回thrill列表中的第二个元素 |
List内部的方法 | 说明 |
count(s => s.length = = 2) | 计算列表中长度为2 String类型元素的个数 |
drop(2) | 从左删除两个元素,返回剩下的 |
dropRight(2) | 从右删除两个元素,返回剩下的 |
exists(s => s = = “aa”) | 判断列表中是否包含“aa”字符串 |
filter(s => s.length = =2) | 将原列表中长度等于2的元素提出来组成一个新的列表返回 |
forall(s => s.endsWith(“a”)) | 判断列表所有元素是不是以“a”结尾 |
foreach(s => printlln(s)) 或 foreach(println) | 打印列表中所有的元素 |
head | 返回列表第一个元素 |
init | 返回列表中除最后一个元素的其他元素 |
isEmpty | 判断列表是否为空 |
last | 返回列表最后一个元素 |
length | 返回列表元素个数 |
map(s => s+”mm”) | 返回列表每一个元素后面加上“mm”的新列表 |
mkString(“,”) | 返回由列表元素组成的字符串 |
remove(s => s.length = = 2) | 去除列表中元素长度为2的元素并返回一个新的列表 |
reverse | 倒序列表中的元素并返回一个新列表 |
sortWith((s , t) => s.charAt(0).toLower <= t.charAt(0).toLower) | 列表中的元素按照第一个字符的小写排序并返回新的列表 |
tail | 返回除列表第一个元素外其他元素组成的新列表 |
九、使用元组(Tuple)
元组也是不可变的,但是可以包含不同类型的元素。元组的实际类型取决于它包含的元素和这些元素的类型。
Eg:val pair = (99 , “Hello”)
pair 类型是 Tuple2[Int , String]
元组的第一个元素是从“1”开始的。
十、使用集(set)和映射(map) :
set可以包含不同类型的元素(val setVal=Set(“aa”,”aa”,99,77,”bb”));map也可以包含不同类型的元素,key和value都可以不一样(val mapVal=Map(3->”a”,6->4,”b”->”v”,”v”->9))list元祖
集合(set)可区分为:可变类型与不可变类型。
可变类型与不可变类型的区别
| 扩展的物质(相当于java中的接口) | “+”方法的使用(为集合增加新元素的方法) |
可变类型 | scala.collection.mutable | 将元素加入到自身 |
不可变类型 | scala.collection.immutable | 创建并返回包含了添加新元素的新集 |
Set类似于java中一样,分为HashSet和TreeSet
映射(map)可分为:可变类型与不可变类型 与set是类似的
十一、学习识别函数式风格
从指令式编程转变到函数式的编程,首先就得尝试着不用任何的var编程。
指令式风格的程序 | 函数式风格的程序(可有副作用) | 函数式风格的程序(没有副作用) |
def printArgs( args : Array[String] ) : Unit={ var i=0 while( i < args.length){ println(args(i)) i+=1 } }
| def printArgs( args : Array[String] ) : Unit={ for( arg <- args){ println(arg) } } 或 def printArgs( args : Array[String] ) : Unit={ args.foreach(println) } | def formatArgs( srgs : Array[String] ) = srgs.mkString(“\n”)
识别是否有副作用:在于其结果是否为Unit |
Scala程序员的平衡感:崇尚val,不可变对象和没有副作用的方法。
十二、从文件里读取文本行
import scala.io.Source
object ReadFileDate {
def main(args: Array[String]){
def widthOfLength(s: String) =s.length.toString.length
if (args.length > 0) {
val lines = Source.fromFile(args(0)).getLines.toList
val longestLine = lines.reduceLeft((a, b) => if (a.length > b.length) aelse b)
val maxWidth = widthOfLength(longestLine)
for (line <- lines) {
val numSpaces = maxWidth -> widthOfLength(line)
val padding = " ".+(numSpaces)
print(padding + line.length + "|" + line)
}
} else
Console.err.println("Please enter filename")
}
}
第四章 类和对象
一、类、字段和方法
1、类:Scala中的类定义和java中的一样,也是用“class”定义的,也可以“new”一个类得到一个对象
Eg:classA{
var num=0
}
使用时: val a=new A()
如果对此类进行实例化得到:
val aVal=new A
varaVar=new A
这其中的aVal.num可以任意赋值,而aVal是不可以再重定向一个新的类。
其中aVar.sum可以任意赋值,aVar也可以再重定向一个新的类。
2、字段:Scala中的字段也可以像java中的字段一样,使用private,protected修饰,但是不能使用public 来修饰。Scala中的默认修饰就是java中的public
3、方法:scala中的方法是由“def”开头的,方法如果有返回值则如下:
private def add(num : Int):Int ={if(num>0)num else num+1}
如果没有返回值的话,写法如下:
def add(num : Int){print(num)}
二、分号推断
Scala程序中的分号是可选择的,如果一行写多语句,那么“;”就是必须的了
如果输入跨越多行的语句时,在scala中不需要特殊处理,scala会在正确的位置分隔语句。
Eg:if(x < 0)
println(“too small”)
else
println(“OK”)
在scala中如果把一条语句拆开写多行时,如果不放到“()”里的话,scala会将一条语句当成多条语句来处理。
Eg: x + y
如果写成: x
+y
Scala会先算 “x”,然后再算 “+y”
如果你非得将一条语句写到现行或是多行以上的话,就得用“()”来标识一条语句的开始和结束。或者是将“+”写到“x”的后面。
三、Singleton对象
在scala中是不能定义静态成员的,而是以定义单例对象来替换。单例对象与类的定义类似,只需要将“class”换成“object”就可以了。
Eg: impot scala.collection.mutable.Map
objectChecksumAccumulator{
private val cache=Map[String, Int]()
def calculate(s : String) : Int={
if (cache.contains(s))
cache(s)
else{
val acc = new ChecksumAccumulator
for(c <- s)
acc.add(c.toByte)
val cs= acc.checksum()
cs
}
}
}
四、Scals程序
在scala程序中,如果想单独运行,则需要创建一个有main方法的单例对象。这和java一样,一个程序的入口都是从main方法开始。(一个scala程序只能有一个main方法,而main方法又必需写在object里;一个scala程序可以有多个object)
Eg: importChecksumAccumulator.calculate
object Summer{
def main(args: Array[String]){
println(arg+”:”+calculate(arg))
}
}
五、Application特质 (一般不推荐这样使用)
在Scala中提供了特质scala.Application。这样可以减少一个输入的工作。定义一个单例,然后继承Application 这样就可以不用写mian方法了。这样比较方便,但是也有其不足之处。如:A.如果想访问命令行参数的话就不能用这种方法了。B.因为某些JVM线程模型里的局限,如对于多线程的程序则要自己写main方法了。C.在某些JVM的实现没有优化被Application特质执行的对象的初始化代码。
Eg: objectDemo extends App{
Console.println("aa")
val fr=newFrench
fr.french;
}