scala
kafka、spark、flink均是scala语言开发的

scala是基于java,可以在scala中使用java语言
scala是以jvm为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言

scala源代码被编译成java字节码文件,然后运行在JVM,可以调用现有的java类库,实现两种语言的无缝对接

scala非常简洁高效,在函数至简原则上体现非常明显,能省则省

scala环境搭建
1、安装jdk
2、下载scala  zip包
3、解压
4、配置scala环境变量
5、测试,cmd窗口输入scala
6、IDEA开发需要安装scala插件

变量和数据类型,这里和java很像

说一下字符串输出,这里和python有点类似
三种方式:
1、字符串,加号拼接 
println(name+" "+age)
2、printf用法,%传值 
printf("name=%s age=%d\n",name,age)
3、字符串模板。$获取变量值
var name = "tom"
var age = 10
println("name=$name , age=$age")

java中有8种基本数据类型,还有引用类型,使用了基本类型的包装类,不是完全的面向对象

scala中一切都是对象,
都是Any的子类,都是Nothing的父类
scala数据类型分为两大类,数值类型AnyVal,引用类型AnyRef

在scala中for循环
for(i <- 1 to 3){
    print(i+" ")
}
to是左右闭合
for(i <- 1 until 3){
    print(i+" ")
}
until是左闭右开

for(i <- 1 to 3 if i != 2){
    print(i+" ")
}
循环守卫

for(i <- 1 to 10 by 2){
    print(i+" ")
}
循环步长

val res = for(i <- 1 to 10) yield i
循环返回值
将遍历过程中处理的结果返回到一个新Vector集合中

import scala.util.control.Breaks
Breaks.breakable(
    for( elem <- 1 to 10){ 
        println(elem)
        if(elem == 3) Breaks.break()
    }
)

函数式编程
基本语法
def sum(x:interesting,y:Int):Int={
    x + y
}

scala函数比较重要知识点比较多的是至简原则

scala函数高级用法
函数值传递 名传递
函数柯里化 闭包
递归
控制抽象
惰性函数

scala面向对象
scala类的构造器:主构造器和辅助构造器
class 类名(形参){//主构造器
    //类体
    def this(形参列表){
        //辅助构造器,可以有多个
    }
}

类的封装:访问权限
类的继承:extends scala是单继承


单例对象
apply方法
通过伴生对象的apply方法,实现不使用new方法创建对象
object Person{
    val country:String = "China"
    
}
1、单例对象采用Object关键字声明
2、单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致
3、单例对象中的属性和方法都可以通过伴生对象名直接调用

主构造器私有
class Person private(cName:String){
    var name:String = cName
}

特质 trait
代替了java中接口的概念

基本语法
trait 特质名{
    trait 主体
}

trait PersonTrait{
    //声明属性
    var name:String = _    
    //声明方法
    def eat():Unit={
    }
    //抽象属性
    var age:Int
    //抽象方法
    def say():Unit
}

class extends 父类 with 特质1 with 特质2

class extends  特质1 with 特质2

所有的Java接口都可以当作Scala特质使用

class Teacher extends PersonTrait with java.io.Serializable

类型检查和转换
obj.isInstanceOf[T]:判断obj是不是T类型
obj.asInstanceOf[T]:将Obj强转成T类型
classOf获取对象的类名

集合
scala集合:序列Seq 集Set 映射Map

不可变数组  Array
val arr = new Array[Int](4)
可变数组ArrayBuffer
import scala.collection.mutable.ArrayBuffer
val arr = ArrayBuffer[Any](1,2,3)

不可变集合List
val list=List(1,2,3,4)
可变集合ListBuffer
import scala.collection.mutable.ListBuffer
val buffer = ListBuffer(1,2,3,4)

不可变集合Set
val set = Set(1,2,3)
可变集合
import scala.collection.mutable.Set
val set = mutable.Set(1,2,3,4)

不可变Map
val map = Map("a"->1,"b"->2,"c"->3)
可变Map
import scala.collection.mutable.Map
val map = mutable.Map("a"->1,"b"->2,"c"->3)

元组
val tuple:(Int,String,Boolean) = (40,"tom",true)
Map中的键值对其实就是元组,只不过元组的元素个数2,称为对偶
访问数据
1、顺序号
println(tuple._1)
2、通过索引访问数据
println(tuple.productElement(0))
3、通过迭代器访问数据
for(elem <- tuple.productIterator){
    println(elem)
}

模式匹配
def des(x:Any) = x match{
    case 5=>"five"
    case "hello" =>"hello"
    case true => "true"
}
模式匹配类型
样例类
case class Person(name:String,age:Int)

object TestGeneric {

  def main(args: Array[String]): Unit = {
    //特殊的模式匹配1   打印元组第一个元素
    for (elem <- Array(("a", 1), ("b", 2), ("c", 3))) {
      println(elem._1)
    }
    for ((word,count) <- Array(("a", 1), ("b", 2), ("c", 3))) {
      println(word)
    }
    for ((word,_) <- Array(("a", 1), ("b", 2), ("c", 3))) {
      println(word)
    }
    for (("a",count) <- Array(("a", 1), ("b", 2), ("c", 3))) {
      println(count)
    }
    println("--------------")
    //特殊的模式匹配2 给元组元素命名
    var (id,name,age): (Int, String, Int) = (100, "zs", 20)
    println((id,name,age))
    println("--------------")
    //特殊的模式匹配3   遍历集合中的元组,给count * 2
    var list: List[(String, Int)] = List(("a", 1), ("b", 2), ("c", 3))
    //println(list.map(t => (t._1, t._2 * 2)))
    println(
      list.map{
        case (word,count)=>(word,count*2)
      }
    )
    var list1 = List(("a", ("a", 1)), ("b", ("b", 2)), ("c", ("c", 3)))
    println(
      list1.map{
        case (groupkey,(word,count))=>(word,count*2)
      }
    )
  }
}

scala异常处理
def main(args:Array[String]):Unit={
    try{
        var n = 10/0
    }catch{
        case ex:ArithmeticException=>{
            //算术异常
            println("发生算术异常")
        }
        case ex:Exception=>{
            //对异常处理
            println("发生异常1")
            println("发生异常2")
        }
    }finally{
        println("finally")
    }
}
Scala没有编译异常的概念,异常都是在运行的时候捕获处理

隐式转换
当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译

一是转换可以在不需要改任何代码的情况下,扩展某个类的功能

隐式函数:使用implicit关键字声明的函数
隐式参数:使用implicit关键字声明的参数
隐式类:使用implicit关键字声明的类


泛型:
协变:class MyList[+T] 子类关系
逆变:class MyList[-T] 父类关系
不变:class MyList[T]  没有关系

泛型上下限:是对传入的泛型进行限定
class P[T<:Person] 泛型上限
class P[T>:Person] 泛型下限

上下文限定:是泛型和隐式转换的结合产物

语法: def f[A:B](a:A)=println(a)//等同于def f[A](a:A)(implicit arg:B[A])=println(a)
使用上下文限定[A:Ordering]之后,方法内无法使用隐式参数名调用隐式参数
需要通过implicitly[Ordering[A]]获取隐式变量

错误示例:
implicit val x:Int = 1
val a = implicitly[Int]
val b = implicitly[Double]

正确示例:
def f[A:Ordering](a:A,b:A) = implicitly[Ordering[A]].compare(a,b)
def f[A](a:A,b:A)(implicitly ord:Ordering[A]) = ord.compare(a,b)

我个人理解是:使用隐式关键字implicit是在正常的逻辑范围外人为提供参数、方法、类