推荐书籍,快学scala
val str="i love scala" //编译器自动确定类型,使用val定义的变量值是不可变的,相当于java里用final修饰的变量
val i = 1
var s="hello" //使用var定义的变量是可变的,再scala中鼓励使用val
val stri: String ="alex" //scala编译器会自动推断变量的类型,必要的时候可以指定类型,变量名在前,类型在后
常用的变量类型: Byte,Char,Short,Int,Long,Float,Double,Boolean
if例子:val y = if(x >0) 1 else -1
if例子:val z=if(x>0) 1 else "error" //在未赋值时,可以是数值,也可以是字符串。但是他的类型变成了"Any"
if例子:val m =if(x >2) 1 //如果x不大于2,那么是未赋值。返回值是m: AnyVal=()。在scala中每个表达式都有值,scala仲有个Unit类,写做(),相当于java中的void
object 单例对象
class 类
trait 相当于java中的接口
块表达式:
object BlockExpressionDemo {
def main(args: Array[String]): Unit = {
val x=0
val result={ //这是一个块表达式,块中最后一个表达式的值就是块的值
if(x<0){
-1
}else if(x>=1){
1
}else {
"error"
}
}
println(result);
}
}
数组例子:
val arr=Array(1,2,3)
val arr2=(1 to 10)
val arr3=Array(1 to 10) //这样是错的,
arr(1)=100
for循环:
1 to 10 //会返回一个scala的Range(1,2,3,4,5,6,7,8,9,10)
for(i <- 1 to 10){
println(i)
}
val a1=(1 to 9)
for(i <- 0 until a1.length) println(i) //打印出来的0-8
高级for循环: //注意:if前面没有分号
for(i<- 1 to 3; j <- 1 to 3 if i!=j){
print((10 * i + j )+" ")
}
for推导式
val v = for (i <- 1 to 10) yield i*10 //yield生成一个新的集合数组
println(v)//会发现v是一个新集合 Vector(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
map例子:
val z=(1 to 10).map(_*10) //也可以写成 (1.to(10).map(_*10),也是返回一个Vector数组
println(z)
val f1=(x:Int) => x * 10
val r= 1 to 10
r.map(f1)
filter例子:
val a1=(1.to(9))
val a2=a1.filter(_%2==0) //filter也是返回一个新数组
until方法:
val a1=(1 to 9)
0 util a1.legnth
for(i <- 0 until a1.length) println(i) //打印出来的0-8
定义方法和函数,函数和方法是有区别的,函数可以作为一个值传到方法里
方法:
def m1(x: Int, y: Int) : Int = x * y //x: Int 参数列表 : Int 方法返回值类型 方法的返回值类型可以不写,编译器可以自动推断,但是对于递归函数,必须指定返回类型
调用val r=m1(3,5)
定义没有返回值的方法:
def m2(name:String): Unit ={
println(name)
}
val v=m2("alex")
print(v)
匿名函数:
val abc=(x:Int,y:Int) => x+y
val func=(x:Int,y:Double) => (y,x) //返回值是一个元组
val func2:(Int,Double) => (Double,Int) = {(a,b) => (b,a) } //(a,b)代表前面(Int,Double)的局部变量 和上面例子的效果一样
简单版匿名函数传入方法的例子:
val f1=(x:Int) => x * 10
val f2=(x:Int) => x+10
val r= 1 to 10
r.map(f1)
r.map(f2)
r.map((x:Int) => x*100) //直接定义一个匿名函数
r.map(x => x*100) //同上面一样效果,更简洁
r.map(_*100) //同上面一样效果,最简洁
val arr=1 to 9
val r1=arr.map(x=>x*5) //产生一个新数组r1
val r2=arr.map(x=>x-1) //产生一个新数组r2
println(r1) //打印数组
println(r1.toBuffer) //把r1变成一个ArrayBuffer
完整版匿名函数传入方法的例子:
object HelloScala{
def main(args: Array[String]): Unit = {
println(m1(func))
}
val func = (x:Int) => x*10
def m1(f:Int => Int) : Int={ //表示需要传入一个Int参数,返回一个Int值,
//在方法体里调用函数
f(3)
}
}
高级版定义匿名函数的例子:
val func:Int => String = { x => x.toString } //传入一个Int =>是返回值,返回一个String 后面必须有大括号函数体 要有一个变量x接收传进来Int,这个x是一个局部变量
调用func(10) 就返回一个String
将方法转换成函数(神奇的下划线)
def m2(x:Int,y:Int) :Int =x+y //定义一个方法
scala> def m2(x:Int,y:Int) :Int =x+y
m2: (x: Int, y: Int)Int
val f2=(a:Int,b:Int) => a+b //定义一个函数
val f3=m2 _ //把方法m2变成了函数
数组,映射,元组,集合
数组:定长数组和变长数组
val arr=new Array[Int](10) //装Int的数组,长度为10,里面值是0
println(arr) //直接打印定长数组,内容为数组的hashcode值
println(arr.toBuffer) //将数组转换成数组缓冲,就可以看到原数组中的内容了,toBuffer会将数组转换成数组缓冲
arr(0)=1 //赋值
arr(1)=2
val arr1=Array(1,3,4,5,6) //定义一个长度为5的数组
val arr2=Array[Int](10) //这里没new,这样只创建了一个长度为1的数组,里面只有一个值为10
println(arr2.toBuffer) //ArrayBuffer(10),长度为1的数组,里面只有一个值为10
变长数组(数组缓冲):
ArrayBuffer,如果想使用数组缓冲,需要导入import scala.collection.mutable.ArrayBuffer包
val ab=ArrayBuffer[Int]()
ab+=1
ab+=(2,3,4,5) //追加多个元素
ab++=Array(6,7) //追加一个数组用两个加号 ++=
ab++=ArrayBuffer(8,9) //追加一个数组缓冲
ab.insert(0,-1,0) //在数组某个位置插入元素用insert ,这里在数组的0下标上插入了两个数字-1和0
ab.remove(8,2) //删除数组某个位置的元素用remove,这里删除了下表8开始的2个元素
遍历数组:
1.增强for循环
val arr=Array(1,2,3,4,5,6)
for(i <- arr)
println(i)
2.好用的uttil会生成脚标,0 until 10 包含0不包含10
for(i <- (0 until arr.length).reverse) //reverse反转
println(arr(i))
val a1=ArrayBuffer(8,2,3)
a1.map(print)
a1.map(println)
a1.map(println(_))
数组的转换:
yield关键字将原始的数组进行转换会产生一个新的数组
val a =Array(1,2,3,4,5)
for(i<- a) yield i * 10
a.map(x=>x*10) //效果和上面相同
a.map((x:Int)=>x * 10) //效果和上面相同
a.map( _ * 10) //效果和上面相同
数组转换小例子:
val arr=Array(1,2,3,4,5,6,7,8,9)
//将偶数取出,再乘以10,生成一个新的数组
val res=for (e <- arr if e%2==0) yield e*10 //第一种方法
arr.filter((x:Int) => x%2 ==0 ) //传进来一个Int,返回一个布尔值 , 最后结果是2,4,6,8
arr.filter(x=> x %2 ==0) //上面的简单版,最后结果是2,4,6,8
arr.filter( _ % 2 ==0) //更简洁版,最后是2,4,6,8
arr.filter( _ % 2 ==0).map( _ * 10) //正确答案
其他例子:arr.sum //返回值45
val arr=Array(2,5,1,4,7,3)
arr.sorted //返回值1,2,3,4,5,6,7
arr.sorted.reverse //返回值7,6,5,4,3,2,1
arr.sortBy(x => x) //返回值1,2,3,4,5,6,7
arr.sortWith( _>_ ) //返回值7,6,5,4,3,2,1 ,从大到小
arr.sortWith( _<_ ) //返回值1,2,3,4,5,6,7,从小到大
arr.sortWith((x,y) => x< y ) //返回值1,2,3,4,5,6,7
映射:
构建映射:
val m=Map("a" -> 1, "b" -> 2) //创建的时候是immutable.Map 不可改变
m("a") //访问
m("a") =2 //报错,不可改变,
import scala.collection.mutable.Map
val mm=Map("i"->1, "j" ->2) //创建的是mutable的map,可以改变
mm("i")=10 //可以
mm("k")=20 //可以
mm+=("o" -> 6) //可以
mm+=(("o",6)) //可以
import java.util.HashMap //可以引入java的包
val hm= new HashMap()
val m = Map(("a",1) ,("b" ,2)) //其实映射里装的是元组,都是对偶元组
访问映射:
m.getOrElse("c",0) //如果m里面没有c,不会报错 ,给他个0
元组:
val t=(1,"spark",2.0) //返回一个(Int, String, Double)
访问:
val r=t._2 //取出spark
val pair=("t",5) //定义一个对偶元组
val m = Map(("a",1) ,("b" ,2))
把上面的pari装入m
m+= pair //res5: m.type = Map(t -> 5, b -> 2, a -> 1)
m+=(("y",6),("z",3)) // res6: m.type = Map(z -> 3, t -> 5, b -> 2, y -> 6, a -> 1)
特殊的例子:
val t=("a", 1, 2.0)
t._2
res0: Int = 1
scala> t._1
res1: String = a
val t,(x,y,z)=("a",1, 2.0)
t: (String, Int, Double) = (a,1,2.0)
x: String = a
y: Int = 1
z: Double = 2.0
scala> x
res2: String = a
将对偶的集合转换成映射:
scala> val arr=Array(("a",1),("b",2))
arr: Array[(String, Int)] = Array((a,1), (b,2))
scala> arr.toMap //转换成了map
res3: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)
拉链操作:
scala> val a=Array("a","b","c")
a: Array[String] = Array(a, b, c)
scala> val b=Array(1,2,3)
b: Array[Int] = Array(1, 2, 3)
scala> a.zip(b)
res4: Array[(String, Int)] = Array((a,1), (b,2), (c,3))
如果拉链多出来一截:
scala> val b=Array(1,2,3,4)
b: Array[Int] = Array(1, 2, 3, 4)
scala> a.zip(b)
res5: Array[(String, Int)] = Array((a,1), (b,2), (c,3)) //多出来的一截自动没有
集合:
集合有三大类:序列Seq,集Set,映射Map,所有集合都扩展子Iterable特质。集合有可变和不可变的两种类型。
val lst=List(1,3,4,5,6)
val list=List(1,2,3)
list(0) //取值
list(0)=10 //报错,不可变
导包:
import scala.collection.mutable.ListBuffer
val lb=ListBuffer(1,2,3)
lb(1)=200 //可以改变值了
scala> lb
res7: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 200, 3)
scala> lb.map(_ * 10) //新生成一个List
res8: scala.collection.mutable.ListBuffer[Int] = ListBuffer(10, 2000, 30)
val lst1=List(1,2,3)
val lst2=0::lst1 //将0插入到lst1的前面生成一个新的List
val lst3=lst1.::(0) //效果同上
val lst4=0+:lst1 //效果同上
val lst5=lst1.+:(0) //效果同上
val lst6=lst1 :+3 //将一个元素添加到lst1的后面产生一个新的集合
val lst0=ListBuffer[Int](1,2,3)
val lst1 = new ListBuffer[Int]
lst1 +=4 //追加4
lst1.append(5) //追加5
lst1 +=(8,9) //追加多个元素
lst2 = ListBuffer(10) //创建一个新集合
lst1 ++=lst2 //把lst2加到lst1里 和 ArrayBuffer里面一样
val lst3=lst1++lst2 //两集合相加,并生成一个新集合
List小例子:
val lst=List(1,3,2,7,5,9,6,4,8) //创建一个List
val lst1=lst.sorted //从大到小排序
val it = lst1.grouped(5) //创建了一个iterator
val lst2=it.toList //查看it里的两个集合,将iterator转换成List, lst2里有两个List,大List套了两个小List
lst2(0) //访问第一个list
val lst3=lst2.flatten //把lst2中的两个小list,平铺成一个大List
例子:单机版WordCount
val lines =List("hello tom hello jerry","hello tom kitty hello hello")
lines.map(_.split(" ")) //用空格来切 ,结果是res35: List[Array[String]] = List(Array(hello, tom, hello, jerry), Array(hello, tom, kitty, hello, hello))
lines.map(_.split(" ")).flatten //上面切完以后,用flatten,编程一个大集合 res36: List[String] = List(hello, tom, hello, jerry, hello, tom, kitty, hello, hello)
//比上面更好的方法
val words=lines.flatMap(_.split(" ")) //flatMap想当与先做了map再做flat操作。
val wordsAndOne = words.map((_,1)) //返回一个List,list里装的是对偶元组。wordsAndOne: List[(String, Int)] = List((hello,1), (tom,1), (hello,1), (jerry,1), (hello,1), (tom,1), (kitty,1), (hello,1), (hello,1))
val grouped = wordsAndOne.groupBy(_._1) //第一个_ 代表每个元组例如(hello,1), 第二个_1代表每个元组里的第一个元素,例如hello。 grouped: scala.collection.immutable.Map[String,List[(String, Int)]] = Map(tom -> List((tom,1), (tom,1)), kitty -> List((kitty,1)), jerry -> List((jerry,1)), hello -> List((hello,1), (hello,1), (hello,1), (hello,1), (hello,1)))
//不用执行,可以看看 val result =grouped.map(_._1) //返回一个List。请比较一下val result =grouped.map(_._2) 的区别。 还有,请试试val result=grouped.keys 这个返回是一个Set(tom,kitty,jerry,hello)
result: scala.collection.immutable.Iterable[String] = List(tom, kitty, jerry, hello)
val result = grouped.map(t => (t._1,t._2.size)) //t是对偶元组tom->List((tom,1),(tom,1)) t._1是key,就是tom, t._2是List,然后取他的size。 最后结果result: scala.collection.immutable.Map[String,Int] = Map(tom -> 2, kitty -> 1, jerry -> 1, hello -> 5)
val finalResult = result.toList.sortBy(_._2) // _是元组,按照次数排序。升序finalResult: List[(String, Int)] = List((kitty,1), (jerry,1), (tom,2), (hello,5))
val finalResult = result.toList.sortBy(_._2).reverse //降序
val finalResult = result.toList.sortBy(_._2).reverse.filter(_._2>1) //过滤1次以上的数据
finalResult: List[(String, Int)] = List((hello,5), (tom,2))
//上面的简化版
val lines =List("hello tom hello jerry","hello tom kitty hello hello")
val grouped = lines.flatMap(_.split(" ")).map((_,1)).groupBy(_._1)
val result=grouped.mapValues(_.size) // _代表每个List,例如List((tom,1),(tom,1)) mapValues不动key,所以还是tom,kitty,jerry等,统计的是values,也就是每个List
fold例子:
val a=Array(1,2,3,4,5,6)
a.sum //21
a.reduce (_+_) //reduce把里面内容进行汇总 ,结果21 (((1+2)+3)+4) 从左开始加 默认调用reduceLeft
a.reduce(_-_) //-19
a.par //返回一个可以并行化操作的集合res0: scala.collection.parallel.mutable.ParArray[Int] = ParArray(1, 2, 3, 4, 5, 6)
a.par.reduce(_+_) //21
fold(10)(_+_) //蜕化。可以传2个参数。
a.fold(10)(_+_) //31 给了个初始值10,
fold也支持并行化计算
a.par.fold(10)(_+_) //61
Set:
不可变的Set: import scala.collection.immutable.HashSet
val set1 = new HashSet[Int]()
//将元素和set1合并生成一个新的set,原有set不变
val set2 = set1 + 4
//set中元素不能重复
val set3 = set1 ++ Set(5, 6, 7)
val set0 = Set(1,3,4) ++ set1
println(set0.getClass)
可变的Set:
import scala.collection.mutable
object MutSetDemo extends App{
//创建一个可变的HashSet
val set1 = new mutable.HashSet[Int]()
//向HashSet中添加元素
set1 += 2
//add等价于+=
set1.add(4)
set1 ++= Set(1,3,5)
println(set1)
//删除一个元素
set1 -= 5
set1.remove(2)
println(set1)
}
Map:也分为可变和不可变
object MutMapDemo extends App{
val map1 = new mutable.HashMap[String, Int]()
//向map中添加数据
map1("spark") = 1
map1 += (("hadoop", 2))
map1.put("storm", 3)
println(map1)
//从map中移除元素
map1 -= "spark"
map1.remove("hadoop")
println(map1)
}
object伴生对象,里面一般存放静态对象,类似于java中的静态变量,静态方法。
scala的hello world
object HelloScala { //object 伴生对象,单例对象
def main(args: Array[String]) { //所有定义在object里的方法,都是静态方法,相当于java中所有方法加上了static
println("hello scala,I love u")
}
}
scala里的类
//在Scala中,类并不用声明为public。
//Scala源文件中可以包含多个类,所有这些类都具有公有可见性。
class Person {
//用val修饰的变量是只读属性,有getter但没有setter
//(相当与Java中用final修饰的变量)
val id = "9527"
//用var修饰的变量既有getter又有setter
var age: Int = 18
//类私有字段,只能在类的内部使用
private var name: String = "唐伯虎"
//对象私有字段,访问权限更加严格的,Person类的方法只能访问到当前对象的>字段
private[this] val pet = "小强"
}
构造器:
注意:主构造器会执行类定义中的所有语句
/**
*每个类都有主构造器,主构造器的参数直接放置类名后面,与类交织在一起
*/
class Student(val name: String, val age: Int){
//主构造器会执行类定义中的所有语句
println("执行主构造器")
try {
println("读取文件")
throw new IOException("io exception")
} catch {
case e: NullPointerException => println("打印异常Exception : " + e)
case e: IOException => println("打印异常Exception : " + e)
} finally {
println("执行finally部分")
}
private var gender = "male"
//用this关键字定义辅助构造器
def this(name: String, age: Int, gender: String){
//每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始
this(name, age)
println("执行辅助构造器")
this.gender = gender
}
}
/**
*构造器参数可以不带val或var,如果不带val或var的参数至少被一个方法所使用,
*那么它将会被提升为字段
*/
//在类名后面加private就变成了私有的
class Queen private(val name: String, prop: Array[String], private var age: Int = 18){
println(prop.size)
//prop被下面的方法使用后,prop就变成了不可变得对象私有字段,等同于private[this] val prop
//如果没有被方法使用该参数将不被保存为字段,仅仅是一个可以被主构造器中的代码访问的普通参数
def description = name + " is " + age + " years old with " + prop.toBuffer
}
object Queen{
def main(args: Array[String]) {
//私有的构造器,只有在其伴生对象中使用
val q = new Queen("hatano", Array("蜡烛", "皮鞭"), 20)
println(q.description())
}
}
6.2.1. 单例对象
在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的
1.存放工具方法和常量
2.高效共享单个不可变的实例
3.单例模式
ackage cn.itcast.scala
import scala.collection.mutable.ArrayBuffer
/**
* Created by ZX on 2015/11/14.
*/
object SingletonDemo {
def main(args: Array[String]) {
//单例对象,不需要new,用【类名.方法】调用对象中的方法
val session = SessionFactory.getSession()
println(session)
}
}
object SessionFactory{
//该部分相当于java中的静态块
var counts = 5
val sessions = new ArrayBuffer[Session]()
while(counts > 0){
sessions += new Session
counts -= 1
}
//在object中的方法相当于java中的静态方法
def getSession(): Session ={
sessions.remove(0)
}
}
class Session{
}
6.2.2. 伴生对象
在Scala的类中,与类名相同的对象叫做伴生对象,类和伴生对象之间可以相互访问私有的方法和属性
package cn.itcast.scala
/**
* Created by ZX on 2015/11/14.
*/
class Dog {
val id = 1
private var name = "itcast"
def printName(): Unit ={
//在Dog类中可以访问伴生对象Dog的私有属性
println(Dog.CONSTANT + name )
}
}
/**
* 伴生对象
*/
object Dog {
//伴生对象中的私有属性
private val CONSTANT = "汪汪汪 : "
def main(args: Array[String]) {
val p = new Dog
//访问私有的字段name
p.name = "123"
p.printName()
}
}
6.2.3. apply方法
通常我们会在类的伴生对象中定义apply方法,当遇到类名(参数1,...参数n)时apply方法会被调用
package cn.itcast.scala
/**
* Created by ZX on 2015/11/14.
*/
object ApplyDemo {
def main(args: Array[String]) {
//调用了Array伴生对象的apply方法
//def apply(x: Int, xs: Int*): Array[Int]
//arr1中只有一个元素5
val arr1 = Array(5)
println(arr1.toBuffer)
//new了一个长度为5的array,数组里面包含5个null
var arr2 = new Array(5)
}
}
6.2.4. 应用程序对象
Scala程序都必须从一个对象的main方法开始,可以通过扩展App特质,不写main方法。
package cn.itcast.scala
/**
* Created by ZX on 2015/11/14.
*/
object AppObjectDemo extends App{
//不用写main方法
println("I love you Scala")
}