Spark高级

SCALA高级

  • 类(class)

  • 抽象类(abstract class)

  • 单例对象(object)

  • 特质(trait)

  • 样例类(case class)

——————————————————————————————————

——————————————————————————————————

1、类Class

  • 没有静态成员和方法

  • 默认构造器就是定义类的的所有语句!!!

  • 辅助构造器在主构造器其中,因为主构造器就是类的定义语句

  • 辅助构造器第一句必须调用其它构造器

//主构造器执行类定义中的所有语句
class Point(var xc: Int, var yc: Int) {
 var x: Int = xc //成员变量
 var y: Int = yc   //可以不写,直接使用xc|yc
 //辅助构造器
 def this() ={
   this(0, 0) //第一句必须调用其他构造器
}
 //成员方法
 def move(dx: Int, dy: Int) ={
   x = x + dx
   y = y + dy
}  
}
var p=new Point()
p=new Point(12,11)

2、继承&重写方法

  • extends实现类的继承

  • 子类重写父类方法必须用override关键字声明

class WhitePoint() extends Point{
   var color="white"
   override def move(dx:Int,dy:Int)={
       x=x+dx
       y=y+dx
       println(color+"chesse move to:"+x+","+y)
  }
}

3、抽象类

  • 抽象类可包含抽象方法

  • 抽象类无法实例化

  • 使用"abstract"关键字修饰

  • 子类重写抽象方法时,override可选

abstract class Shape{
def draw():Unit
}
class Square extends Shape{
//省略构造器
   //抽象方法的重写,override可省略
   override def draw:Unit={
  println("draw a square")
}
   //省略构造器
var shape=new Square //多态,指向子类的父类引用
shape.draw //无参方法,省略()
}

4、单例对象

  • Scala的类中无法定义静态成员,即无static关键字。

  • 没有构造器,所有不能有参数

  • 使用object关键字定义单例对象,像Java一样表达类的静态成员变量、成员方法与静态代码块

  • 单例成员相当于JAVA中类的单例模式(印证于其转换为class后全都加上了static)

  • 第一次运行时执行所有代码,之后调用只能取值或函数

  • main()方法必须定义在单例对象中

  • 单例对象与同名类定义在同一文件中时形成绑定关系(伴生类)

!!!!单例对象就是java中全是static和final的一种类!!!
object Blah {
 println("Blah initializing...")
 def sum(l: List[Int]): Int = l.sum
}
test.Blah.sum(List[Int](1, 2, 3, 4, 5))

5、伴生

  • 单例对象与同名 类 定义在同一文件中时形成伴生绑定关系

  • 伴生类与伴生对象可相互访问各自私有的成员(单例对象通过apply函数生成实例才可以访问类的成员,此时生成的就是一般的java类)

  • 伴生对象可为伴生类增加静态成员

    !!伴生就是java中的一般类,既有静态方法和成员又有普通方法和成员!!!

    通过aplly方法和unapply方法实现两者的耦合,apply方法又提供了省略new的语法糖,使用感觉更像是一体的了

//单例对象通过apply方法返回一个伴生类的实例
//apply方法是关键字方法,默认返回同名类的new实例
//单例对象.apply()等价于 单例对象()

class Student(n: String, a: Int) {
 private var name = n    //私有变量,伴生对象可以访问
 private var age = a
}
//伴生对象
object Student {
 def apply(n: String, a: Int): Student = new Student(n, a)
 def main(args: Array[String]): Unit = {
   val stu=Student("Jason",9)  
   //通过伴生对象的apply()方法创建实例,省略了创建类实例时候的new Student()的new
   println(stu.name)
}
}

5、特质trait(接口)

  • 特质用于在类之间共享程序接口和字段,类似Java接口

  • 特质是字段和方法的集合,可以提供字段和方法实现(!!!!可以实现!!!)

  • 类和单例对象都可以扩展特质(extends)

  • 特质不能被实例化,因此没有构造参数,类似Java接口

  • 特质使用“trait”关键字定义

  • 实现|覆盖特质中的方法使用“override“关键字,变量常量也是一样的

demo实例

//大部分性质与java中的接口是类似的
//唯一不同在于trait可以实现函数或者定义变量
trait Pet{
   val name:String
   def cry():Unit
}
class Dog(val name: String) extends Pet{
 override def cry()=println("wow ...")
}
val dog = new Dog("Harry")
val animals = ArrayBuffer.empty[Pet]
animals.append(dog) //多态
animals.foreach(pet => {println(pet.name);pet.cry()}) //子类的方法

 

6、混入特质(mix in trait)

多重继承(trait):一个类只能有一个父类,但是可以继承多个trait

(想想trait和java接口的关系,但是trait可以实现方法和变量,所以用的也是extends关键字,称之为混入!)

  • 既然用的是extends那么instanceof trait必然是true

  • 类的混入时构造顺序从左向右,同一父类只会被构造一次

abstract class A {
 val message: String
}
class B extends A {
 val message = "I'm an instance of class B"
}
trait C extends A {
 def loudMessage = message.toUpperCase()
}
class D extends B with C //静态混入
val d = new D
println(d.messge)  // I'm an instance of class B
println(d.loudMessage)  // I'M AN INSTANCE OF CLASS B

 

7、可替换混入

  • 可替换的trait特性,一次定义,多种混入组合(必须是子类trait)

  • OTS:(继承也可以多态啦啦啦啦)

//类必须有声明从那个特质映射
class Drawing{
    self:Shape=>   	//Shape是特质名,self指自身
    //这句话声明将Shape特质的结构映射到本类
    //既不继承也不实现,但可以提前编写调用trait的方法和变量的语句
    //至于这些方法具体的实现,由使用时动态混入的特质决定(多态)
    //目的:trait的多态混入。
    def start():Unit=draw()
    def stop():Unit=draw()
}
trait Shape {//父trait
  def draw(): Unit
}
trait Square extends Shape {//子trait
  def draw(): Unit = println("draw a square")
}
trait Triangle extends Shape {//子trait
  def draw(): Unit = println("draw a triangle")
}
//动态混入
(new Drawing() with Square).start()
(new Drawing() with Triangle).start()

8、选择结构

1、Try

解决函数可能会判处异常的问题,成功则返回值,失败则如何

返回类型:

  • Success

  • Failure

2、Either

解决返回值不确定的问题,可以有两种返回值

返回类型:

  • Left:

  • Right:

3、Option

解决空指针问题

返回类型:

  • Some

  • None

9、样例类(case class) 重点

  • 主要用于模式匹配match

  • 常用于描述不可变的值的对象,数据完全依赖构造参数

  • 构造参数默认为val常量,因此样例类默认不可变,通过模式匹配可分解出数值

  • 只关心类中的值而不在意函数方法,类似javabean

  • 自动创建伴生对象

  • 自动实现方法toString|equals|copy

  • 关键方法:

    • apply

    • unapply

  • 两个样例类“==”操作时,通过按值比较而不是按引用

与class的区别:

如果一个类内部存在计算和其他复杂的行为,那它应该是class

10、模式匹配 match 重点

!!!模式允许任何类型!!!

  • 基本模式匹配

//基本模式匹配
def matchTest(x: Int): String = x match {
  case 1 => "one"
  case 2 => "two"
  case _ => "many"
}
matchTest(3)  // many
matchTest(1)  // one

  • 模式守卫匹配

//模式守卫(在模式后面加上if 条件)
def matchTest2(x: Int): String = x match {
  case i if i==1 => "one"
  case i if i==2 => "two"
  case _ => "many"
}
matchTest2(3)  // many
matchTest2(1)  // one

  • 仅类型匹配

//仅匹配类型
def matchTest3(x: Any): String = x match {
  case x:Int => "Int"
  case x:String => "String"
  case _ => "Any"
}
matchTest3(3.0)  // Any
matchTest3(1)     // Int

  • 样例类的组合匹配

//样例类的模式匹配
case class Student(_name:String,_age:Int) {
  var name=_name
  var age=_age
}
def matchTest4(x: Student)= x match {
  case Student(name,19) => println(name)
  case Student("Tom",age) => println(age)
  case Student(name,age) => println(name,age)
  case _ => println("no matches")
}
matchTest4(Student("Jason",19))
matchTest4(Student("Tom",20))
matchTest4(Student("Jimmy",20))

11、提取器对象Object 重点

  • 对应样例类case class,相当于自定义的case class

  • 单例对象中指定unapply()方法时,称为提取器对象(Extractor Objects)

  • unapply()方法接受一个实例对象,返回最初创建它所用的参数

  • unapply()相当于数学中的反函数,根据映射结果反转映射关系求原数据

class Student(_name:String,_age:Int) {
  var name=_name
  var age=_age
}
object Student{
  def apply(name: String, age: Int): Student = new Student(name, age)
  def unapply(arg: Student): Option[(String, Int)] ={
    if(arg==null) None else Some(arg.name,arg.age)  
}
    
def matchTest(x:Student)=x match {
    case Student(name,age) if age<=20 => println("young man")
    //自动调用unaplly方法,返回的是个Option类
    //apply是根据参数new类,很容易推理出unapply是根据对象获取参数
    case Student(name,age) if age>20 => println("old man")
}
matchTest(Student("Jason",19))   //res0:young man

 

12、泛型

  • 泛型类

  • 泛型函数

  • 基本与java相同

13、型变(泛型)

  • 协变

    Class demo[+T] {}  //+表示的应该是同向型变
    class b {}
    class a extends b{}
    //demo[a]是demo[b]的子类型,称之为协变
    
  • 逆变

    //与协变相反
    class demo[-T]{} //反向型变
    //demo[a]是deme[b]的父类
    
  • 类型边界

    class demo[T<:A] //泛型限定为类型A的子类,上界
    class demo[T>:A] //泛型新丁为类型A的父类,下界
    //编译期间检查,IDE不一定检查
    

14、内部类

  • 与java内部类基本类似,但有很一点很不同:

    • scala的内部类是绑定到类的实例对象而不是类上

    • 因此同类的不同的实例对象的内部类被认为是不同的类

    • 可以认为内部类的类名是 实例hash+内部类名

15、正则 重点

  • r插值,保留原字符串不转义(用于保留正则字符中的转义)

    r"\w\d\s"
    //\w不会被scala转义成其他字符
    
  • s插值,字符串中可以使用$引用变量

    s"$JAVA_HOME"
    //输出的是/opt/jdk
    
  • "str".r 将任何一个字符串转换为Regex类的实例对象

  • API

    • 都是regex类的方法

    //findAllMatchIn() 返回所有的匹配结果(Interator【Match】)
    val regex="abc".r
        regex.findAllMatchIn("abc@qq.com").foreach(
          x=>{
            println(x.group(0),x.toString())
          }
     	)
    
    //findFirstMatchIn() 返回第一个结果,返回类型是Option[Match]
    print(regex.findFirstMatchIn("abc@qq.com").getOrElse("not matched"))
    
    //findAllIn() 返回所有匹配的结果(Interator【String】)
    regex.findAllIn("abc@qq.com1huyang@cc.com").foreach(x=>{println(x)})
    //最后一个是空
    
  • Regex类的模式匹配

    val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
    "2014-05-23" match {
        case date(_*) => println("It is a date")
    }
    "2014-05-23" match {
        case date(year, _*) => println("The year of the date is " + year) 
    } 
    "2014-05-23" match {
        case date(year, month, day) => println(year,month,day)
    }
    
    //此处regex就是个自定义的extractor提取器,返回的是regex的构造参数即各个组的值
    //g1,g2是str中的()分组
    
  • 分组demo

    //方式一 ,不推荐,太多了
    case class Log(level:String,date:String,uri:String)
    object Father{
      def main(args: Array[String]): Unit = {
        val log=
          """
            |INFO 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=31
            |INFO 2016-07-25 requestURI:/c?app=0&p=2&did=18005472&industry=469&adid=31
            |ERROR 2016-07-25 requestURI:/c?app=0&p=1&did=18005472&industry=469&adid=32
          """.stripMargin
        val pattern="(?<level>\\w+)\\s(?<date>\\d{4}-\\d{2}-\\d{2})\\s[^:]+:(?<uri>.+)".r("level","date","uri")
        var logs:ListBuffer[Log]=ListBuffer[Log]()
        
          pattern.findAllMatchIn(log).foreach(x=>{
          logs+=Log(x.group("level"),x.group("date"),x.group("uri"))
        })
        logs.foreach(x=>{
          println(x.level,x.date,x.uri)
        })
      }
    }
    
    //方式二,推荐
    pattern.findAllMatchIn(log).map(x=>{
            Log(x.group("level"),x.group("date"),x.group("uri"))
        }).foreach(x=>{
          logs.append(x)
        })
    

     

16、集成JAVA API

  • Scala无缝集成JavaAP

import java.text.SimpleDateFormat
import java.util.{Calendar, Date}
val dateFmt = "yyyy-MM-dd"
def today(): String = {
    val date = new Date
    val sdf = new SimpleDateFormat(dateFmt)
    sdf.format(date)
}

 

posted @ 2019-08-28 15:39  WhoYoung  阅读(592)  评论(0编辑  收藏  举报