在这里插入代码片
# Scala快速入门
概述
开发: Spark Kafka Flink
安装
- jdk8
- IDEA上安装Scala
添加国内镜像
~/.sbt/repositories
[repositories]
local
aliyun: https://maven.aliyun.com/nexus/content/groups/public/
central: https://repo1.maven.org/maven2/
[repositories]
local
Nexus osc : https://code.lds.org/nexus/content/groups/main-repo
Nexus osc thirdparty : https://code.lds.org/nexus/content/groups/plugin-repo/
typesafe: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext], bootOnly
typesafe2: http://repo.typesafe.com/typesafe/releases/
sbt-plugin: http://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/
sonatype: http://oss.sonatype.org/content/repositories/snapshots
uk_maven: http://uk.maven.org/maven2/
ibibli: http://mirrors.ibiblio.org/maven2/
repo2: http://repo2.maven.org/maven2/
comp-maven:http://mvnrepository.com/artifact/
store_cn:http://maven.oschina.net/content/groups/public/
store_mir:http://mirrors.ibiblio.org/maven2/
store_0:http://maven.net.cn/content/groups/public/
store_1:http://repo.typesafe.com/typesafe/ivy-releases/
store_2:http://repo2.maven.org/maven2/
sbt-releases-repo: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]
sbt-plugins-repo: http://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]
maven-central: http://repo1.maven.org/maven2/
[repositories]
local
aliyun: https://maven.aliyun.com/nexus/content/groups/public
typesafe-ivy-releases: https://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext], bootOnly
sonatype-oss-releases
maven-central
sonatype-oss-snapshots
修改配置文件
sbt/conf/sbtconfig.txt
# sbt configuration file for Windows
# Set the java args
-Xms1024m
-Xmx1024m
-Xss4M
-XX:ReservedCodeCacheSize=128m
# Set the extra sbt options
-Dsbt.log.format=true
-Dsbt.boot.directory=C:/Users/Administrator/.sbt/boot
-Dsbt.ivy.home=C:/Users/Administrator/.ivy2
-Dsbt.global.base=C:/Users/Administrator/.sbt
-Dsbt.repository.config=C:/Users/Administrator/.sbt/repositories
# -Dsbt.log.format=true
###入门
-
val vs var
val: 值 final val 值名称:类型 = 值 var: 变量 var 值名称:类型 = 值 //:类型可以自动推导
-
基本类型
Byte/Char
Short/Int/Long/Float/Double
Boolean
-
lazy在Scala中的使用
lazy在声明时不会初始化, 在使用时才会初始化(延时加载)
lazy val a = 1 a: Int = <lazy> a Int = 1
Scala函数
-
函数/方法定义
def 方法名(参数名:参数类型): 函数返回类型 = { //最后一行时返回值, 不需要return }
-
默认参数设置(设置函数缺省值)
def sayName(name:String = "PK"): Unit { name }
-
可变参数
def sum(numbers:Int*) = { var result = 0 for(number <- numbers) { result += number } result }
-
-
条件表达式
if(){} else {}
-
循环表达式
Range(start, end, step != 0) = 1 until 10 = 1.until(10)//左闭右开 1 to 10 = 1.to(10)//左闭右闭 //for 循环 for(i <- 1 to 10 if i % 2 == 0) { println(i) //2, 4, 6, 8, 10 } //数组遍历 val courses = Array("Hadoop", "Spark SQL") courses.foreach(course => println(course))
Scala面向对象
-
面向对象概述
-
封装
- 属性、分发封装到类中
-
继承
- 父类和子类的关系(子类可以重写父类的方法)
-
多态
- 父类引用指向子类对象
Student extends People People people = new People(); Student student = new Student(); People people = new Student();
-
-
Scala Class
-
定义
class People { var name:String = "" val age = 10 private [this] val gender = "male" def printInfo(): Unit = { println("gender:" + gender) } def eat():String = { name + "eat..." } def watchFootball(teaName:String): Unit = { println(name + "has watching..." + teaName) } }
-
构造器
-
class Person(val name:String, val age:Int){// 主构造器 //附属构造器(多个附属构造器参数不同) def this(name:String, age:Int, gender:String) { this(name, age) //附属构造器第一行代码必须调用主构造器或其他附属构造器 this.gender = gender } }
-
-
继承
-
class Person(val name:String, val age:Int) {...} class Student(name:String, age:Int, var major:String) extends Person(name, age){...} //子类继承若父类的构造器参数有val则子类不用加, 子类特有的则需要加val/var外部才能访问
-
重写父类属性和方法需要 override 关键字修饰
-
-
抽象类(类的一个或多个方法没有完整实现)
-
abstract class Person { def speak val name:String val age:Int } //使用Person(子类继承实现) class Student extends Person { override def speak = { } override val name:String = "xxx" override val age:Int = 118 }
-
-
伴生类和伴生对象
-
//伴生类和伴生对象例子 class ApplyTest { } object ApplyTest { }
-
Apply
-
main { //调用对象中的方法 for(i <- 1 to 10) { ApplyTest.incr } println(ApplyTest.count) //10 说明object本身是一个单例对象 val b = ApplyTest() //Object.apply val c = new ApplyTest() c() //Class.apply } class ApplyTest { def apply() = { println("Class ApplyTest apply...") } } object ApplyTest { var count = 0 def incr = { count = count + 1 } //一定是apply方法 //最佳实践:在Object new class def apply() = { println("Object ApplyTest apply...") //在object中的apply中new class new ApplyTest } }
-
-
-
-
case class(用于模式匹配)
-
case class Dog(name:String) //使用 println(Dog("旺财").name)
-
Trait(特征)
-
trait类似于接口
-
-
//例子 xxx extends ATrait with BTrait with CTrait ```
-
Scala集合
-
数组
-
//1 val a = new Arrya[type](length) a(0) = "hello" a(0) //hello //2 val b = Array("hello") val c = Array(2, 3, 4, 5, 6, 7, 8, 9) c.mkString(",") //"2, 3, 4, 5, 6, 7, 8, 9" c.mkString("<", ",", ">") //"<2, 3, 4, 5, 6, 7, 8, 9>"
-
可变数组
-
val c = scala.collection.mutable.ArrayBuffer[Int]() //数组中加入元素 c += 1 //c:1 c += (1, 2, 3, 4, 5) //c: 1,1,2,3,4,5 c ++= Array(6, 7, 8) //c: 1,1,2,3,4,5, 6, 7, 8 //++= 传入定长数组 //删除元素 -= --= c.remove(1) //c:1,2,3,4,5, 6, 7, 8 c.remove(0, 3) //c:5, 6, 7, 8 c.trimEnd(2) //c: 5,6 //变为不可变数组 c.toArray
-
-
-
List
-
val l = List(1, 2, 3, 4, 5) l.head //1 l.tail //2, 3, 4, 5 val l2 = 1 :: Nil //l2: List(1) 将冒号左边作为头右边作为tail拼成list //可变list var l = scala.collection.mutable.ListBuffer[type]() //递归求和 def sum(nums:Int*):Int = { if(nums.length == 0) { 0 } else { nums.head + sum(nums.tail:_*) //nums.tail : seq //:_* seq => Int } }
-
-
Set
-
val set = Set(1, 2, 3, 4, 5) //set无重复且无序
-
-
Map
-
var map:Map[char, Int] = Map() //key唯一键不唯一 var colors1 = Map("red" -> "#FF0000", "azure" -> "#F0FFFF") var colors2 = Map("blue" -> "#0033FF", "azure" -> "#F0FFFF") //添加 += map += ('I' -> 1) //方法 keys values isEmpty colors.keys colors.values, colors.isEmpty //Map合并(合并时会移除重复的key) var colors = colors1 ++ colors2 colors = colors1.++(colors2) //Map遍历 colors.keys.foreach{ i => print("key = " + i) println("Value = " + colors(i)) } //查看Map中存在指定的key colors.contains("red") //return boolean
-
-
Option(选项)
-
Option类型用来表示一个值是可选的。
-
Option[T]是一个类型为T的可选值的容器:若值存在则Option[T]为一个Some[T], 若不存在, Option[T]就是对象None
-
val myMap: Map[String, String] = May("key1" -> "value1") val value1: Option[String] = myMap.get("key1") val value2: Option[String] = myMap.get("key2") println(value1) //Some("value1") println(value2) //None println(value1.get) //value1 println(value2.get) //Exception println(myMap.getOrElse("key1", "key2")) //Some("value1") println(myMap.getOrElse("key2", "None")) //None
-
-
Turple(元组)
-
元组也是不可变的,但与列表不同的是元组可以包含不同类型的元素
-
val t = (1, 3.14, "Rua") val t = new Turple3(1, 3.14, "Fred") //元组的实际类型取决于它的元素的类型,比如 (99, "runoob") 是 Tuple2[Int, String]。 ('u', 'r', "the", 1, 4, "me") 为 Tuple6[Char, Char, String, Int, Int, String]。 //目前 Scala 支持的元组最大长度为 22。对于更大长度你可以使用集合,或者扩展元组 //访问元组中的元素 t._1 //1 t._2 //3.14 //迭代元组 val t = (4, 5, 2, 3) t.productIterator.foreach(i => println("Value = " + i)) //4, 5, 2, 3
-
模式匹配
-
普通类型匹配
-
val names = Array("Akiho Yoshizawa", "YuiHatono", "Aoi Sola") val name = names(Random.nextInt(names.length)) name match { case "Akiho Yoshizawa" => println("吉") case "YuiHatono" => println("波") case "Aoi Sola" => println("苍") case _ => println("xxx") }
-
加条件匹配
-
def judgeGrade(name:String, grade:String): Unit { grade match { case "a" => println("a") case _ if(name == "lise") => println("lisi") case _ => println("d") } }
-
-
-
Array模式匹配
-
def greeding(array:Array[String]): Unit = { array match { case Array("zhangsan") => println("zhangsan") case Array(x, y) => println(x + y) case Array("zhangsan", _*) => println("zhangsan and others") case _ => println("everybody") } }
-
List模式匹配
-
def greeding(list: List[String]): Unit = { list match { case "zhangsan" :: Nil => println("zhangsan") case x::y::Nil => println("Hi:" + x + "," + y) case "zhangsan" :: tail => println("hello others") case _ => println("Hi: everybody") } }
-
-
-
变量类型匹配
-
def matchType(obj:Any): Unit = { obj match { case x:Int => println("Int" + x) case s:String => println("String:" + s) case m:Map[_, _] => m.foreach(println) case _ => println("other type") } } val m = Map("key" -> "value") matchType(m) //print: (key, value)
-
-
Scala异常处理
-
try { //open file //use file val i = 10 / 0 println(i) } catch { case e:ArithmeticException => println("除数不能为0") case e:Exception => println(e.getMessage) } finally { //释放资源 close file }
-
-
case class匹配
-
def caseClassMatch(person: Person): Unit = { person match { case CTO(name, floor) => println("CTO name:" + name + ", Floor:" + floor) case Employee(name, floor) => println("Employee name:" + name + "Floor:" + floor) case _ => println("others") } } class Person case class CTO(name:String, floor:String) extends Person case class Employee(name:String, floor:String) extends Person case class Others(name:String, floor:String) extends Person caseClassMatch(CTO("rua", "22"))
-
声明case class时, 自动发生一下过程
- 构造器的每个参数都成为val,除非显式被声明为var,但是并不推荐这么做;
- 在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象;
- 提供unapply方法使模式匹配可以工作;
- 生成toString、equals、hashCode和copy方法,除非显示给出这些方法的定义。
-
-
Some/None(Option[T])模式匹配
-
object Test { def main(args: Array[String]) { val sites = Map("runoob" -> "www.runoob.com", "google" -> "www.google.com") println("show(sites.get( \"runoob\")) : " + show(sites.get( "runoob")) ) println("show(sites.get( \"baidu\")) : " + show(sites.get( "baidu")) ) } def show(x: Option[String]) = x match { case Some(s) => s case None => "?" } }
-
可以避免使用null关键字而是返回一个对象
-
Scala函数高级操作
-
字符串高级操作
-
插值:
-
val name = "eugeo" println(s"Hello:$name") // Hello:eugeo
-
-
多行字符串:
-
val b = """ |多行字符串 |hello |world |""".stripMargin //多行字符串""""""
-
-
-
匿名函数
-
(x:Int) => x+1 {(x:Int) => x+1} val f1 = (x:Int) => x+1 def add = (x:Int, y:Int) => {x+y} //将匿名函数作为参数传给一个函数
-
-
curry函数:
-
def sum(a:Int, b:Int) = a+b println(sum(2, 3)) //5 def sum2(a:Int)(b:Int) = a+b println(sum2(2)(3)) //5
-
-
高阶函数
-
map
-
val l = List(1, 2, 3, 4, 5, 6, 7, 8) l.map((x:Int) => x+1) //(2, 3, ..., 9) = l.map((x) => x + 1) = l.map(x => x+1) = l.map(_ + 1) l.map(_+1).foreach(println) // (2,3,4, ..., 9)
-
filter(过滤器)
-
l.map(_ * 2).filter(_ > 8).foreach(println) //10, 12, 14, 16
-
-
-
reduce
-
println(l.reduce(_ - _)) // -34 println(l.reduceLeft(_ - _)) // (((1 - 2) - 3) - 4 )... //-34 println(l.reduceRight(_ - _))// (1 - (2 - (3 - 4)))... //-4
-
fold
-
l.fold(0)(_ - _) //-36 = 0-1-2-3-4-5-6-7-8 l.fold(10)(_ - _) //-26 = 10-1-2-3-4-5-6-7-8 //同样有foldLeft和foldRight
-
-
-
flatten(展平)
-
val f = List(List(1,2),List(3,4)) //List[List[Int]] f.flatten //List(1,2,3,4) f.map(_.map(_ * 2)) //List(List(2,4),List(6,8)) f.flatMap(_.map(_*2)) //List(2,4,6,8)
-
-
-
偏函数
-
部分函数
def sum(x:Int, y:Int, z:Int) = x+y+z val tb1 = sum_ tb1(1,2,3) //6 val tb2 = sum(_:Int, 2, 3) tb2(1) //6
-
偏函数
- 对给定的输入参数类型,函数可接受该类型的任何值。换句话说,一个(Int) => String 的函数可以接收任意Int值,并返回一个字符串。
- 对给定的输入参数类型,偏函数只能接受该类型的某些特定的值。一个定义为(Int) => String 的偏函数可能不能接受所有Int值为输入。
- 通过isDefineAt()来判断输入值是否应该由当前偏函数进行处理
- andThen组合偏函数,设计本质接近Pipe-and-Filter模式,每个偏函数都可以理解为是一个Filter。
val positiveNumber:PartialFunction[Int, Int] = { case x if x > 0 => x } val zero:PartialFunction[Int, Int] = { case x if x == 0 => 0 } val negativeNumber:PartialFunction[Int, Int] = { case x if x < 0 => -x } def abs(x: Int): Int = { (positiveNumber orElse zero orElse negativeNumber)(x) }
-
隐式转换
-
隐式值(隐式参数)
将p变量标记为implicit,所以编译器会在方法省略隐式参数的情况下去搜索作用域内的隐式值作为缺少参数。
但是如果此时你又在REPL中定义一个隐式变量,再次调用方法时就会报错
def name(implicit name: String) = name implicit val p = "mobile" println(name) //mobile / def name(implicit name: String) = name implicit val p = "mobile" implicit val p1 = "abc" println(name) //error could not find implicit value for parameter name: String
隐式转换必须满足无歧义规则,在声明隐式参数的类型是最好使用特别的或自定义的数据类型,不要使用Int,String这些常用类型,避免碰巧匹配
-
隐式视图
- 隐式视图,是指把一种类型自动转换到另外一种类型,以符合表达式的要求
- 隐式类型转换是编译器发现传递的数据类型与申明不一致时,编译器在当前作用域查找类型转换方法,对数据类型进行转换。
- 隐式类型转换:
implicit def double2Int(d: Double): Int = d.toInt var i:Int = 3.5 println(i) //3
-
隐式方法调用:
- 隐式方法调用是当编译器发现一个对象存在未定义的方法调用时,就会在当前作用域中查找是否存在对该对象的类型隐式转换,如果有,就查找转换后的对象是否存在该方法,存在,则调用。
object Test { class Horse { def drinking(): Unit = { println("I can drinking") } } class Crow {} object drinking{ // 隐式方法调用 implicit def extendSkill(c: Crow) = new Horse() } def main(args: Array[String]): Unit = { // 隐式转换调用类中不存在的方法 import drinking._ var crow = new Crow() crow.drinking() //I can drinking } }
-
隐式类
-
概述: Scala 2.10引入了一种叫做隐式类的新特性。隐式类指的是用implicit关键字修饰的类。在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换。
object Test { class Crow {} object crow_eval{ implicit class Parrot(animal: Crow) { //隐式类声明 def say(say: String): Unit = {println(s"I have the skill of Parrot: $say")} } } def main(args: Array[String]): Unit = { // 隐式类 import crow_eval._ crow.say("balabala") } }
-
隐式类注意事项:
- 构造参数有且只有一个,且为非隐式参数
- 隐式类必须被定义在类、伴生对象和包对象里
- 隐式类不能是
case class
(case class
会自动生成伴生对象,与上一条矛盾) - 作用域内不能有与之同名的标识符
-
-
隐式转换前提条件
- 不存在二义性
- 隐式操作不能嵌套使用,比如需要
C
类型参数,而实际类型为A
,作用域内存在A => B
,B => C
的隐式方法,Scala编译器不会尝试先调用A => B
,再调用B => C
。 - 代码能够在不使用隐式转换的前提下能编译通过,就不会进行进行隐式转换