类型
1.基本类型
和Java类似,scala也有基本类型,但是scala的基本类型也是对象,String类型是直接引用的Java的string,举个栗子(scala脚本):
scala> val num = 2 + 3
num: Int = 5
//等价于
scala> val num = (2).+(3)
num: Int = 5
基本操作符都是方法,定义在scala.基本类型里面,比如+ - * / ,也有一些稍微复杂的操作定义在富包装类中,以‘Rich+基本类型定义’,比如max min等
可变和不可变对象
函数式语言强调对象不可变,方法无副作用。
用val定义不可变对象,不可变对象初始化值时需要赋初值。
用var定义可变对象,可随时赋值
类型推演
三目运算符
Java:a > b ?a : b
scala: if(a>b) a else b
控制结构
for循环生成器
java: for(int i=1; i<=5; i++)
scala:for(i <- 1 to 5 by 1)
for守卫表达式
java: for(int i=1; i<=5 && i%2 == 0; i++)
scala: for(i <- i to 5 by 1 if i%2 == 0)
for推导式
var arr = for(i <- 1 to 5 by 1 if (i%2) == 0) yield{ println(i); i}
异常
java:
try{}
catch(NullPointerException e1){}
catch(FileNotFoundException e2){}
finally{}
scala:
try{}
catch{
case e1:NullPointerException => {}
case e2:FileNotFoundException => {}
}
finally{}
break and continue
import util.control.Breaks._
var arr = Array(1,3,9,5)
breakable {
for (i <- arr)
if (i > 5) break
else println(i)
}
println("continue...")
//continue语句
for (i <- arr)
breakable{
if (i> 5) break
else println(i)
}
模式匹配
1.Java的switch case语句,同时也支持守卫,和for循环类似
var num = 10;
num match {
case _ if(num % 2 == 0) => println("偶数")
case _ if(num %2 != 0) => println("奇数")
case _ => println("default")
}
2.case类
case类是经过优化的类,会自动重载很多有用的方法比如:toString、equals、hashcode ,更重要的是,case类会自动生成伴生对象(object classname;apply方法)
数据结构
数组
//定义
var arr = Array(1,2,3)
var arr = new Array[Int](3)
//赋值
arr(0) = 12
//二维数组
var arr = Array.ofDim[Int](3,4)
arr(0)(1) = 10
元组
不同类型的数据的集合
val tuple = ("learn scala",56.2)
println(tuple._1+":"+tuple._2)
容器
可变容器和不可变容器.常见的List、Vector是不可变容器,Map、Set等既有可变的,也有不可变得
import scala.collection.immutable._
import scala.collection.mutable._
序列
List的定义和使用
//list1和list2的内容不可变
var list1 = List(1,2,3)
//Nil是一个空链表,list2=List(4,5,6)
var list2 = 4::5::6::Nil
var list3 = 7::8::list1
Vector
var vector = Vector(3, 4)
//向前添加
println(1 +: 2 +: vector)
//向后添加
println(vector :+ 5 :+ 6)
Range
Range是一种带索引的不可变等差数列,上面的1 to 5 by 1就是一个Range对象
包含起点,不包含终点的range:1 until 5 by 1
Set和Map
Set:var set = Set("Apache","Hadoop","Spark")
Map:var map = Map(1->"first",2->"Second")
迭代器
类和方法
方法
定义方式:def 方法名(参数名:参数类型, 参数名:参数类型,......):返回值类型 = {方法体}
简写方式:
- 无参数可以不加方法名后面的括号;
- 返回值类型也可以不写,通过推演得出;
- 方法体如果只有一句话,也可以不写花括号;
- 最后的返回值可以不写return关键字。
- 在类中定义的方法,可以使用中缀表示法简写
比如:def print = println("Hello Wolrd")
类
类的定义:
和Java类似的定义类的方式
访问权限:public(默认访问方式)、private、protected。当属性为private访问属性时,一般都会提供get和set方法,scala的getter和setter定义方式如下
class Person(var name:String){
private var _age = 0
def age = _age
def age_=(a:Int) = _age = a
}
构造器
定义主构造器:class 类名(var|val 属性名:类型......)
定义在主构造器的和在类内部声明为public访问权限的属性都默认提供了getter和setter方法,以对象名.属性名的方式访问
例如
scala> class Counter(var count:Int)
defined class Counter
scala> var counter = new Counter(10)
counter: Counter = Counter@435a2c7d
//访问
scala> println(counter.count)
10
定义辅助构造器:def this(参数列表){}
第一个辅助构造器必须依赖主构造器,第二个辅助构造器必须依赖于第一个辅助构造器,以此类推。例如:
class Person() {
private var _age = 0
private var _name = ""
def this(age: Int) {
this()
_age = age
}
def this(age: Int, name: String) {
this(age)
_name = name
}
}
对象
1.伴生对象和孤立对象
伴生对象是伴生类的单例对象,没有定义伴生类的单利对象称为孤立对象。伴生对象的定义方式为:
//object People是class People的伴生对象,也是单例对象。同时在伴生对象中还可以实现static关键字,因为一个类只能生成一个伴生对象,而在伴生对象中定义的public方法和属性就是static的
class People{}
object People{
def eat = {println("people eat")}
}
//call
People.eat()
2.apply方法
apply定义在伴生对象中,可以通过类名.apply()形式调用,但是也可以省略apply,直接类名+参数的形式调用。apply方法可以重载
class Animal(name:String){
}
object Animal{
def apply(param:String) = new Animal(param)
}
//call
val dog = Animal("dog")
3.unapply方法
unapply方法同apply方法一样定义在伴生对象中,不同的是,unapply用于提取类的属性
class Animal(val name:String){
}
object Animal{
def apply(param:String) = new Animal(param)
def unapply(a :Animal) :Option[(String)] = Some((a.name))
}
//call
val Animal(name) = Animal("dog")
//name属性的值被提出来
println("animal's name="+name)
类和特质
抽象类
抽象类需要加abstract关键字,在类中定义的属性不赋初值,即为抽象字段;方法不定义方法体为抽象方法
扩展类通过关键字extend继承抽象类,其中,抽象类和抽象字段可以不使用override关键字修饰,但是抽象类里面的非抽象方法必须通过关键字abstract实现
abstract class AbsCar {
val name:String
def print():Unit
def geeting = println("welcome to my car")
}
class BMWCar extends AbsCar {
val name: String = "BMW"
def print: Unit = println("car name is " + name)
override def geeting: Unit = super.geeting
}
option类
在返回值可能为null的情况下,尽可能将返回值包装为Option类型,这样,在获取返回值的时候,可以使用getOrElse方法获取一个默认对象,而不是判断是否为空或者出现nullPointExcption
trait特质
使用trait声明一个特质,特质和接口类似。
当只有一个基类需要继承,或者只有一个trait需要混入时,子类使用extend关键字。但是当有多个特质需要混入时,应该extend后加with关键字,声明需要混入的特质
函数
在面向过程(C语言)和面向对象(C++、Java)的编程语言中,值、结构体、对象是可以赋值传递的。在函数式语言中,函数也是可以通过赋值来传递的,类似于C的函数指针,但是更强大
函数变量
方法(函数)定义:
def counter(num:Int):Int = num + 1
和变量的定义相似,函数也有类型和值。参数类型Int+返回值类型Int构成了函数的类型,函数的值就是入参num+函数体。由此,我们可以这样定义一个函数:
//变量名num:变量类型Int = 变量值10
val num:Int = 10
//变量名counter:变量类型(Int => Int) = 变量值(value) => {value+1}
val counter:(Int => Int) = (value) => {value+1}
lambda表达式
函数有匿名函数,就是无需定义函数名的函数,也就是lambda表达式。
匿名函数的定义:(参数名:参数类型,参数名:参数类型...) => {函数体}
(value:Int) => {value/2}
下划线
_标识那些在函数中只出现一次的变量,比如:
//等价于lambda表达式:(value:Int) => value+1
(_:Int) + 1
高阶函数
//2的x次方
def powerOfTow(x: Int): Int = if (x <= 0) 1 else x * powerOfTow(x - 1)
//l+(l+1)+...r
def sumInts(l: Int, r: Int): Int = if (l > r) 0 else l + sumInts(l + 1, r)
//l的平方+(l+1)的平方+..+r的平方
def sumSequars(l: Int, r: Int): Int = if (l > r) 0 else l * l + sumSequars(l + 1, r)
//2的l次方+2的(l+1)次方+...+2的r次方
def sumPowerofTwo(l: Int, r: Int): Int = if (l > r) 0 else powerOfTow(l) + sumPowerofTwo(l + 1, r)
//高阶函数,参数也是函数
def sum(f: Int => Int, l: Int, r: Int): Int = if (l > r) 0 else f(l) + sum(f, l + 1, r)
println(sum(x => x, 1, 5))
println(sum(x => x * x, 1, 5))
println(sum(powerOfTow, 1, 5))
容器的遍历和映射
val f = println(_:Int)
val list = List(1,2,3)
list.foreach(f)
println(list.map(a => a * 2))
val strs = List("Apache","Hadoop","spark")
println(strs.flatMap(a => a.toList))
filter和reduce
val list = List(1, 2, 3, 4, 5);
println(list.filter(i => i%2 == 0))
println(list.reduce((a,b) => a+b))
println(list map (_.toString) reduce ((x, y) => s"f($x,$y)"))
println(list reduceLeft (_ - _))
println(list reduceRight (_ - _))
println(list.fold(10)(_ * _))