目录
1.Scala六大特征
- Java和scala可以无缝混编,都是运行在JVM上的;
- 类型推测,不用指定类型;
- 并发和分布式(Actor,类似java多线程Thread);
- 特征trait,类似java的interface和abstract结合;
- 模式匹配,match case,类似java的switch case;
- 函数式编程,类似C的函数;
2.Scala数据类型
- Scala所有类型都是类,Scala中Any是顶级父类,就是任意类型;
- Any下面两个体系 值类型(AnyVal)和引用类型(AnyRef);
- 把数值类型(Int Boolean char..)这一些归为值类型(AnyVal);
- 把String和数组,列表等归为引用类型(AnyRef);
- Null是一个类,在Java和Scala中小写的null是一个值,大写的Null是一个类,不允许再被继承,是一个终止的特征,继承了引用类型(AnyRef);
- Nothing是所有类型的子类,没有实例对象;
- Unit代表的是一个值类型,类似void。
3.常量和变量
- var声明变量,可修改;
- val声明常量,一次赋值,不可修改;
- var和val后都可不必指定数据类型,scala自行类型推断。
4.类和对象
- class:成员变量都是非static,可创建多个对象,没有main方法(main是static);
- object:成员变量都是static,单例模式;
- case:样例类,类似java的entity,默认实现了toString、equals、copy和hashCode等方法。创建对象时可以用new,也可以不用;
object caseClassTest {
def main(args: Array[String]): Unit = {
val s1 = Student(1,1)
val s2 = new Student(1,1)
println(s1.toString)
println(s1.equals(s2))
}
}
//样例类Student
case class Student(id:Int, age:Int)
- apply方法:class和object都可以定义apply方法,apply方法本质上来说就是可以直接用类名()或对象名()来直接调用的方法。
class Person {
var name = "zs"
var age = 10
def apply() = {
println("class person apply")
}
}
object Person {
def apply() = {
println("object person apply")
new Person()
}
}
object Test {
def main(args: Array[String]): Unit = {
//调用object person apply
val person = Person()
//调用class person apply
person()
}
}
5.条件判断
与java一致。
6.循环
6.1to和until
/**
* to和until
* 例:
* 1 to 10 返回1到10的Range数组,包含10
* 1 until 10 返回1到10 Range数组 ,不包含10
*/
println(1 to 10)//打印 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
println(1 to (10,2))//步长为2,从1开始打印 ,1,3,5,7,9
println(1 until 10) //不包含最后一个数,打印 1,2,3,4,5,6,7,8,9
println(1 until (10,3))//步长为3,从1开始打印,打印1,4,7
6.2for
//可以分号隔开,写入多个list赋值的变量,构成多层for循环
//可以在for循环中加入条件判断
for(i <- 1 to 10; j <- 1 until 10;if (i%2) == 0){
println("i="+ i +",j="+j)
}
/*
* yield 关键字
* 1-100集合中的偶数存储到另一个集合
* yield关键字能够将符合要求的元素自动封装到一个集合中
*/
val rest = for(i <- 1 to 100; if i%2 == 0) yield i //此时rest就为选择出的i构成的一个集合
for(elem <- rest)
println(elem)
6.3while和do while
与java一致。
7.函数
函数格式: def 函数名(参数):返回值 = {函数体}
7.1普通函数
//函数定义
def fun (a: Int , b: Int) : Unit = {
println(a+b)
}
//调用方式
fun(1,1)
7.2递归函数
/**
* 递归函数
* 5的阶乘
*/
def fun2(n :Int) :Int= { //必须写返回值类型
if(n == 1)
n
else
n * fun2(n-1)
}
println(fun2(5))
7.3参数默认值函数
/**
* 包含参数默认值的函数
* 1. 函数的参数有默认值,在调函数的时候可以传参,也可以不传参,
* 2. 若不传参使用的默认值,
* 3. 如果传参,默认值会被覆盖
*/
def fun2(num1:Int = 10,num2:Int = 20) = {
num1 + num2
}
//调用函数
fun2()
7.4可变参数个数的函数
参数中加*,表示参数个数可变,函数参数可以是一个也可以是多个,随机灵活的。
def fun5(args:Double*) = {
/**
* 在scala中
* +=前后的数值类型必须一致
* +前后的数值类型可以不一致
*/
var sum = 0.0
for(arg <- args){
sum += arg
}
sum
}
println(fun5(1.8,2.2,3.3))
7.5匿名函数
格式为:val 函数名 = (参数) => {函数体}
/**
* 匿名函数
* 1.有参数匿名函数
* 2.无参数匿名函数
* 3.有返回值的匿名函数
* 注意:
* 可以将匿名函数返回给定义的一个变量
* 匿名函数不能显式声明函数的返回类型
*/
//有参数匿名函数
val value1 = (a : Int) => {
println(a)
}
//无参数匿名函数
val value2 = ()=>{
println("我爱Angelababy")
}
//有返回值的匿名函数
val value3 = (a:Int,b:Int) =>{
a+b
}
value1(1)
value2()
println(value3(4,4))
7.6嵌套函数
/**
* 嵌套函数:在函数体内又定义了一个函数
*/
def fun7(n:Int)={
def fun8(a:Int,b:Int):Int={
a + b
}
fun8(n,1)
}
println(fun7(10))
7.7 偏应用函数
当多次调用某个函数,且函数的某个参数一直不变时,可以定义偏应用,写死不变的参数,只填写变化的参数。
//定义正常函数
def log(date :Date, s :String)= {
println("date is "+ date +",log is "+ s)
}
以下为main中调用部分:
//出现多次调用函数,且第一个参数不变的情况
val date = new Date()
log(date ,"log1")
log(date ,"log2")
log(date ,"log3")
//定义偏应用函数logWithDate,写死第1个参数,只要传入第2个参数
//下划线相当于占位符的作用,手动传入即可
val logWithDate = log(date,_:String)
logWithDate("log11")
logWithDate("log22")
logWithDate("log33")
7.8高阶函数
函数的参数或返回值是函数。
//以下函数有2个参数,参数1是函数,参数2是Int数值
def hightFun(f:(Int,Int) => Int, a:Int) : Int = {
f(a,100)
}
//作为参数的函数定义
def f(v1 :Int,v2: Int):Int = {
v1+v2
}
//函数调用
hightFun(f, 1)
7.9柯里化函数
不懂
8.字符串
8.1String
创建不可变字符串对象,使用与java类似,如下所示:
val s1 = " Abc "
val s2 = "abc"
//equals判断两个值是否相同
println(s1.equals(s2))
//equalsIgnoreCase判断两个值是否相同,忽略大小写
println(s1.equalsIgnoreCase(s2))
//trim去掉前后空格
println(s1.trim)
//indexOf字符串中与传入的assci码相同的值的下标
println(s1.indexOf("b"))
8.2StringBuilder
创建可变字符串对象,使用也是与java类似。
val s = new StringBuilder();
//append用于附加信息
s.append("abc")
//+同样也可附加信息
s += 'd'
println(s)
9.数组
关键字Array。
- 一维数组
/**
* Array关键词 创建一个长度为10 的Int类型的数组
* 如果创建了一个Int类型的数组,那么初始值都是0
* String类型的数组,初始是null
* Boolean类型的数组,初始是false
*/
val nums = new Array[Int](10)
for(i <- 0 until nums.length){
nums(i) = i * i
}
nums.foreach {println}
- 二维数组
暂时不管。
10.集合
Scala的集合类如下:
Seq、Set、Map都继承自Iterable。
10.1 Seq
Seq是元素可重复的集合。
Scala的Seq类似Java的List,是Trait类型的。
其子类大致分为两大类,索引序列和线性序列。
- 索引序列意味着随机存取是最高效的,当创建一个IndexedSeq时,默认会创建一个Vector的列表。
scala> val x = IndexedSeq(1,2,3)
x: IndexedSeq[Int] = Vector(1, 2, 3)
- 线性序列说明集合可以很方便的被分辨为头尾部分,并且用head、tail和isEmpty方法是很常见的。当创建一个LinearSeq时会创建一个list的列表。
scala> val seq = scala.collection.immutable.LinearSeq(1,2,3)
seq: scala.collection.immutable.LinearSeq[Int] = List(1, 2, 3)
10.1.1 List
val list1 = List(1,2,3,4,5)
//contains判断是否存在参数值的元素
println(list1.contains(6))
//drop丢弃前面n个元素
list1.drop(2).foreach { print }
println()
//take获取前面n个元素
list1.take(3).foreach(print)
println()
//map用于List元素一一映射
list1.map {x=> x +","}.foreach(x=>print(x))
list1.map {_ +","}.foreach(x=>print(x))
println()
//exists判断是否存在符合条件的元素
println(list1.exists { x => x > 300 })
val list2 = List("hello world", "ni hao")
//flatmap用于List元素扁平化映射
//_可以替换x=>x,其中_的位置与第二个x相同
list2.flatMap(x=>x.split(" ")).foreach(x=>println(x))
list2.flatMap(_.split(" ")).foreach(println(_))
10.1.2 ListBuffer
val listBuffer = new ListBuffer[String]
listBuffer += ("hello")
listBuffer += ("bj")
listBuffer.foreach { print }
println
listBuffer -= ("hello")
listBuffer.foreach { print }
10.2 Set
Set集合是元素不可重复的集合。
//创建Set
val set1 = Set(1,2,3,4,4)
val set2 = Set(1,2,3)
//遍历(Set会自动去重)
//方式一:foreach
set1.foreach(println)
//方式二:for
for(s<-set1) {
println(s)
}
//常用方法
//交集
set1.intersect(set2).foreach(print)
println()
set1.&(set2).foreach(print)
println()
//判断是否是子集
println(set1.subsetOf(set2))
println()
//差集
set1.diff(set2).foreach(print)
println()
set1.&~(set2).foreach(print(_))
println()
//最大值
println(set1.max)
//最小值
println(set1.min)
//转成数组
set1.toArray.foreach(print)
println()
//转成List
set1.toList.foreach(print)
println()
//转成字符串mkString
println(set1.mkString(" "))
10.3 Map
Map是key-value格式的集合。
val map = Map(
"name" -> "houpk",
"age" -> 35,
"sex" -> "male"
)
//根据key获取value
println(map("name"))
//遍历
//方式一
val keys = map.keys
val iterator = keys.iterator
while (iterator.hasNext) {
val key = iterator.next()
println(map(key))
}
//方式二
for (k<-map) {
println(k._1+","+k._2)
}
/*
Map中的方法 :
1. filter:过滤,留下符合条件的记录
2. count:统计符合条件的记录数
3. contains:map中是否包含某个key
4. exist:符合条件的记录存在不存在
*/
map.filter(x=>x._1.equals("name")).foreach(println)
println(map.count(_._1.equals("name")))
println(map.contains("name"))
println(map.exists(_._1.equals("name")))
11 元组
元组类似数据库的表,元组中的元素就是表的字段。关键字为Tuple,使用小括号封装。
//创建元组
val t2 = Tuple2(1, "hello")
val tt2 = (1,"hello")
val t3 = Tuple3(1,2,"hello")
val tt3 = (1,2,"hello")
//元组遍历
val tupleIterator = tt3.productIterator
while (tupleIterator.hasNext) {
println(tupleIterator.next())
}
//swap用于tuple2元素交换位置
val swap2 = t2.swap
println(swap2._1 + "," + swap2._2)
12 Trait
- Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。与接口不同的是,它还可以定义属性和方法的实现。是抽象类和接口的结合。
- 一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承
- Trait的继承用extends关键字继承,多继承时多个Trait之间用with连接。
- Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait。
- 继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。
- trait中不可以传参数。
trait Read {
val readType = "read"
val gender = "m"
def read(name:String): Unit = {
println("i am read " + name)
}
}
trait Listen {
val listenType = "Listen"
val gender = "m"
def listen(name:String): Unit = {
println("i am listen " + name)
}
}
class Person() extends Read with Listen {
override val gender = "n"
}
object test{
def main(args: Array[String]): Unit = {
val person = new Person()
person.read("abc")
person.listen("def")
println(person.gender)
}
}
13 模式匹配
- 类似java的switch case;
- Scala除了匹配值,还可以匹配类型,类型的匹配必须要有变量名;
- 匹配项使用关键字case;
- 匹配项后跟表达式,使用=>隔开匹配项和表达式;
- 表达式不需要break,会自动break
def main(args: Array[String]): Unit = {
val tuple = (1,2,3f,"4",5d)
val iterator = tuple.productIterator
while (iterator.hasNext) {
matchTest(iterator.next())
}
}
def matchTest(x:Any) = {
x match {
case 1 => println("x is 1")
case x:Int => println("x type is Int")
case _ => println("not match")
}
}
14 并发编程Actor
https://www.cnblogs.com/yinzhengjie/p/9376296.html
Scala在2.11.x版本中将Akka加入其中,作为其默认的Actor。
Actor类似java的Thread,每个Actor将状态和行为封装在一个轻量的进程/线程中,不和其他Actor分享状态,当需要与其他Actor交互时,通过发送消息/事件实现。
Actor特征总结如下:
- Actor间通信是消息机制,每个Actor都有自己的消息队列,进来的消息按先来后到排列;
- 消息发送是异步的,非阻塞的;
- 消息一旦发送成功,不能修改;
首先在dependency中添加依赖:
<!-- 添加akka的actor依赖 -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.11</artifactId>
<version>2.4.17</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_2.11</artifactId>
<version>2.4.17</version>
</dependency>
使用代码如下:
object ActorTest {
def main(args: Array[String]): Unit = {
//创建线程池对象MyFactory,用来创建actor的对象的
val MyFactory = ActorSystem("ActorTest")
//通过MyFactory.actorOf方法来创建一个actor,注意,Props方法的第一个参数需要传递我们自定义的HelloActor类,
//第二个参数是给actor起个名字
val p1 = MyFactory.actorOf(Props[Actor1], "player1")
//给actor p1发送消息
p1 ! "start"
p1 ! "hello"
p1 ! "stop"
}
}
class Actor1 extends Actor {
override def receive: Receive = {
case "start" => {
println("start")
}
case "stop" => {
println("end")
context.stop(self)
context.system.terminate() // 关闭ActorSystem,即关闭其内部的线程池(ExcutorService)
}
case _ => {
println("sorry,i cannot follow you")
}
}
}
15 隐式转换
隐式转换关键字implicit,在编写程序的时候可以尽量少的去编写代码,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量。
隐式转换分为三类:隐式值、隐式视图、隐式类。
15.1 隐式值
使用implicit修饰变量,当缺失变量造成编译出错时,默认使用这个变量。
//参数前使用implicit关键字
def sayName(implicit name:String): Unit = {
println(name)
}
def main(args: Array[String]): Unit = {
/* 将变量声明为implicit,编译器在执行sayName方法时发现缺少一个String类型的参数,此时会搜索作用域内类型为String的隐式值,并且将搜索到的隐式值作为sayName的参数值 */
implicit var s = "Angelababy"
sayName
}
15.2 隐式视图
使用implicit修饰方法,当编译出错时,默认会调用这个方法。
def main(args: Array[String]): Unit = {
/* addNum参数是String,直接调用会报错,在编译的时候,发现作用域内
有一个隐式方法,正好这个方法的参数是String 返回值是Int,此时
调用隐式方法,返回一个Int值,再将Int传给addNum */
implicit def string2Int(num:String) = Integer.parseInt(num)
addNum("1000")
}
def addNum(num:Int): Unit = {
num + 1000
}
15.3 隐式类
隐式类就是使用implicit修饰类,当编译出错时,默认转换为定义的隐式类。
隐式类必须被定义在类,伴生对象和包对象里;
其所带的构造参数有且只能有一个。
package com.moshi.test
object ImplicitTest {
def main(args: Array[String]): Unit = {
/**
* "abc"这个字符串想要调用getLength,但是自己没有实现这个方法
* 发现作用域内有一个隐式转换的类,类的构造函数的参数是String类型
* "abc"传给构造函数,得到这个类的对象,从而调用getLength方法
*/
import com.moshi.test.Util._
"abc".getLength()
}
}
object Util{
//定义隐式类,构造函数的参数为String
implicit class Int2String(s:String) {
def getLength()= s.length
}
}
https://blog.csdn.net/hjy1821/article/details/83751384