scala--处理大数据

2019-09-18写Mac终端运行scala

mac命令行编译执行运行scala文件;Scala编译和运行


3.检验结果
在终端输入scala 命令进入scala解释器然后输入12
4.退出scala解释器
输入 :q    或:quit 

编译src下的scala
scalac -classpath lib/spark-assembly-1.5.1-hadoop2.6.0.jar -d classes src/com/xzj/process/*

classes文件夹下面就会有相应的.class文件
scala -classpath classes:lib/spark-assembly-1.5.1-hadoop2.6.0.jar com.xzj.process.Main

➜  scala git:(master) ✗ cd /Users/tianzi/Desktop/时间复杂度/scala 
➜  scala git:(master) ✗ scala s_name.scala 
hello	world
  • scalac:scala的编译器
  • -classpath:指明外部依赖包
  • -d:指明 编译后的输出文件 要放到哪里,这里把编译结果放在classes文件下
  • 最后指明需要编译的scala文件(该例子是整个目录)。

s_name.scala 文件

必须是双引号


println("hello	world")

package com.xx.yy
import java.util._;
object HelloWorld {
        def main(args: Array[String]) {
                println("Hello World!");
        }
}

项目的结构src

 |--com
     |--xzj
          |--process
               |--Main.scala
               |--NAStatsCounter.scala

NAStatsCounter.scala内容

package com.xzj.process
import org.apache.spark.util.StatCounter
class NAStatsCounter extends Serializable {

  val stats: StatCounter = new StatCounter()
  var missing: Long = 0

  def add(x: Double): NAStatsCounter = {

    if (java.lang.Double.isNaN(x)) {
      missing += 1
    } else {
      stats.merge(x)
    }
    this
  }

  def merge(other: NAStatsCounter): NAStatsCounter = {
    stats.merge(other.stats)
    missing += other.missing
    this
  }

  override def toString = {
    "stats: " + stats.toString + "NaN: " + missing
  }
}

object NAStatsCounter extends Serializable {
  def apply(x: Double) = new NAStatsCounter().add(x)
}

Main.scala内容

package com.xzj.process
object Main {
  def main(args: Array[String]) {

    var testArray = Array(11.1, 12.1, 13.2, Double.NaN)
    var test2 = Array(11, 3, 22.1, Double.NaN, 0)

    var testc = testArray.map(c => NAStatsCounter(c))
    var testc2 = test2.map(NAStatsCounter(_))
    var list = testc.zip(testc2)
    list.map {
      case (a, b) => a.merge(b)
    }
    list.foreach(println)
  }

}

安装

首先,确保安装了Java 8 JDK。
要检查,请打开终端并键入:
java -version(确保您拥有1.8版本。)
(如果您没有安装它,请在此处下载Java。)

然后,安装Scala:
通过安装诸如IntelliJ的IDE或sbt,Scala的构建工具。

如果您熟悉命令行,则最好;下载SBT
在命令行上使用Scala和sbt入门
在命令行上使用sbt和ScalaTest测试Scala

各工具的版本

  • Scala : 2.12.6
  • Sbt : 1.1.6
  • IDEA : 2018.1.4
  • Atom : 1.23.2
  fibncci.github.io git:(master) brew -v
Homebrew 2.1.11
Homebrew/homebrew-core (git revision b669; last commit 2019-09-05)
  fibncci.github.io git:(master) brew info scala   
scala: stable 2.13.0
JVM-based programming language
https://www.scala-lang.org/
Required: java >= 1.8 
To use with IntelliJ, set the Scala home to:		目录
  /usr/local/opt/scala/idea
build_error: 0 (30 days)		构建错误:0(30)

  fibncci.github.io git:(master) brew install scala
使用homebrew安装scala sdk和可以构建scala应用的工具
Pruned 14 symbolic links and 1 directories from /usr/local

  fibncci.github.io git:(master) brew list 
scala	tree	unrar

  fibncci.github.io git:(master) brew install sbt@1
==> Downloading https://github.com/sbt/sbt/releases/download/v1.3.0/sbt-1.3.0.tg
######################### 100.0%
curl:	卷曲		 增删改查  CRUDcreate, read, update, delete
🍺  /usr/local/Cellar/sbt/1.3.0: 765 files, 54.9MB, built in 2 minutes 51 seconds

  ~ git:(master)  cd  /Users/tianzi/Documents/scala

cd到一个空的目录运行如下命令创建一个模板工程
  scala git:(master)  sbt new scala/hello-world.g8
[info] Set current project to scala (in build 
name [Hello World template]: 
# 直接回车使用默认工程名即可
# 回车后多一个 hello-world-template   
Template applied in /Users/tianzi/Documents/scala/./hello-world-template

2.cd到hello-world-template目录并运行sbt命令进入sbt的交互模式
  scala git:(master)  cd hello-world-template 
  hello-world-template git:(master)  sbt                         
[info] [launcher] getting org.scala-sbt sbt 1.2.8  (this may take some time)...
...
[info] Running Main 
Hello, World!
[success] Total time: 20 s, completed 2019-9-18 8:32:30
1. Waiting for source changes in project hello-world-template... (press enter to interrupt)

                                 
  hello-world-template git:(master)  scala -version
Scala code runner version 2.13.0 -- Copyright 2002-2019, LAMP/EPFL and Lightbend, Inc.
  hello-world-template git:(master)  scala         
Welcome to Scala 2.13.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_181).
Type in expressions for evaluation. Or try :help.

scala> 1+2
res0: Int = 3

笔记

Scala语言的名称来自于“可伸展的语言”。它是一种把面向对象和函数式编程理念加入到静态类型语言中的 混血儿。它跑在标准的 Java 平台上,可以与所有的 Java 库实现无缝 交互。它也是用来编写脚 把 Java 控件链在一起的很好的语言。但是用它来建立大系统 和可重用控件的架构将更能够发挥它的力量。

Scala介绍 ;Scala是基于JVM的一种编程语言 1.Scala的六大特征

  1. Java和Scala可以无缝衔接

  2. 类型推测(自动推测类型)

  3. 并发和分布式(Actor)

  4. 特质(trait),特征(类似于java中interfaces和abstract结合)

  5. 模式匹配(类似于java中的switch)

  6. 高阶函数

1. Scala的安装

   1.环境变量
   1.官网下载scala:https://www.scala-lang.org/download/all.html
   2.解压zip或双击msi包
   查看版本号scala -version

2.开发环境
方法一:
       1.下载scala插件(对应eclipse版本):http://scala-ide.org/download/prev-stable.html
       2.解压zip,将features和plugins文件夹拷贝到eclipse安装目录下的dropins/scala。若没有该目录,自行创建
       
   方法二:
       西在Scala IDE:http://scala-ide.org/download/sdk.html
   方法三:
       1.安装IDEA
       2.打开IDEA,点击Configure->Plugins,搜索Scala,点击Install安装
       3.设置JDK,点击Configure->Project Defaults->Project Structure
       4.创建Scala项目,点击Create New Project->Scala->Scala。
   5.更改SDK版本号,点击Browse,选择本地安装的Scala目录,选择System
   

Scala基础

  • Byte Char Short Int Long Float Double Boolean 这些都是类
  • String: 使用底层的 java.lang.String 表示字符串,但通过 StringOps 类为字符串追加上百种操作
数据类型 描述
Byte 8bit的有符号数字
Short 16 bit 有符号的数字
Int 32 bit 有符号的数据
Long 64 bit 有符号的数字
Float 32 bit IEEE 754 单精度浮点数
Double 64 bit IEEE 754 双精度浮点数
Char 16 bit Unicode字符
String 字符串
Boolean 布尔类型
Unit 表示无值,和其他语言中void等同
Null 空值或者空引用。Trait,其唯一实例是null,是AnyRef的子类
Nothing 所有其他类型的子类型,表示没有值。Trait,所有类型(包括AnyRef和AnyVal)的子类,没有实例
Any 所有类型的超类,任何实例都属于Any类型
AnyRef 所有引用类型的超类
AnyVal 所有值类型的超类
None Option的两个子类之一,另一个是Some,用于安全的函数返回值
Nil 长度为0的List

2.变量和常量的声明 定义常量或者变量的时候,也可以写上返回的类型,一般省略,如:val a;Int = 10

常量不可在赋值

/**
 * 变量:用var定义,可修改
 * 常量:用val定义,不可修改
 * /
var age = 10
val name = "zhangsan"

3.类和对象 创建类

class Person{
  val name = "zhangsan"
  val age = 18
  def sayName() = {
    "my name is "+ name
  }

创建对象

object Lesson_Class {
   def main(args: Array[String]): Unit = {
    val person = new Person()
    println(person.age);
    println(person.sayName())
  }
}
伴生类和伴生对象

class Person(xname :String , xage :Int){
  var name = Person.name
  val age = xage
  var gender = "m"
  def this(name:String,age:Int,g:String){
    this(name,age)
    gender = g
  }
  def sayName() = {
    "my name is "+ name
  }
}
object Person {
  val name = "zhangsanfeng"
  def main(args: Array[String]): Unit = {
    val person = new Person("wagnwu",10,"f")
    println(person.age);
    println(person.sayName())
    println(person.gender)
  }
}

如果在同一个文件中,object对象和class类的名称相同,则这个对象就是这个类的伴生对象,这个类就是这个对象的伴生类。可以互相访问私有变量

Apply方法

object ScalaDemo01 { def main(args: Array[String]): Unit = { val p = new Person(“zs”,19) val person = Person(“wagnwu”,10) } } class Person(xname :String , xage :Int){ val name = “zs” val age = xage var gender = “m” def this(name:String,age:Int,g:String){ this(name,age) gender = g } } object Person{ def apply(name:String,age:Int)={ new Person(name,age) } }

使用apply方法,实现对象时可以不用加new scala中object时单例对象,相当于java中的工具类,可以看成是定义静态的方法的类,object不可以传参数。另外,Trait不可以传参数 Scala中的class类默认可以传参数,默认的传参数就是默认的构造函数。重写构造函数的时候,必须调用默认的构造函数。 class类属性自带getter、setter方法 使用object时,不用new;使用class时要用new,并且new的时候,class中除了方法不执行,其他都只执行

4.判断if…else


val age =18 
if (age < 18 ){
	println("no allow")
}else if (18<=age&&age<=20){
	println("允许与其他")
}else{
	println("允许自我")
	}

5.循环

​ for、while、do…while

1.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
res10: scala集合不可变范围包含= Range 1 to 10
res10: scala.collection.immutable.Range.Inclusive 


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.to(10, 2)) 

println(1 until 10 ) //不包含最后一个数,打印 1,2,3,4,5,6,7,8,9
println(1.until(10))//与上面等价
println(1 until (10 ,3 ))//步长为2,从1开始打印,打印1,4,7

for 循环

/**
 * for 循环
 * scala中 不能写count++ count-- 只能写count+
 */
for( i <- 1 to 10 ){
  println(i)
}
/**
* 多层for循环
 * 可以分号隔开,写入多个list赋值的变量,构成多层for循环
 * /
//例子: 打印小九九
for(i <- 1 until 10 ;j <- 1 until 10){
  if(i>=j){
	  print(i +" * " + j + " = "+ i*j+"	")
  }
  if(i==j ){
    println()
  }
}
 /**
 * 可以在for循环中加入条件判断
 * /
for(i<- 1 to 10 ;if (i%2) == 0 ;if (i == 4) ){
  println(i)
}
/**
 * 将for中的符合条件的元素通过yield关键字返回成一个集合
 */
 val list = for(i <- 1 to 10  ; if(i > 5 )) yield i

3.while循环

/**
 * while 循环
 */
var index = 0 
while(index < 100 ){
	println("第"+index+"次while 循环")
  index += 1 
}
index = 0 
do{
	index +=1 
	println("第"+index+"次do while 循环")
}while(index <100 )

Scala函数 1.定义 Scala函数根据有无参数划分为有参函数和无参函数

/**
 * Scala函数的定义
 */
def fun (a: Int , b: Int ) : Unit = {
   println(a+b)
 }
fun(1,1)
    
def fun1 (a : Int , b : Int)= a+b
    println(fun1(1,2))  

注意: 1.函数的定义语法,用def来定义 2.可以定义传入的参数,要指定传入参数的类型 3.方法可以写返回值的类型也可以不写,函数会根据返回值自动判断,有时候不能省略,必须要写!!!例如:在递归函数中或者函数的返回值是函数类型 4.Scala中函数有返回值时,可以写return,也可以不写return。如果不写return,会将函数的最后一行当作结果返回。当写return时,必须要写函数的返回值 5.如果返回值可以一行搞定,可以将{}省略不写 6.传递给方法的参数可以在方法中使用,并且scala规定方法的传过来的参数为val的,不是var的 7.如果去掉方法体前面的等号,那么这个方法的返回类型必定是Unit的。这种说法无论方法体里面什么逻辑都成立,scala可以把任意类型转换为Unit。假设,里面的逻辑最后返回了一个String,那么这个返回值会被转换位Unit,并且值会被丢弃

2.递归函数

 /**
   * 递归函数 
   * 5的阶乘
   */
 def fun2(num :Int) :Int= {
    if(num ==1)
      num
    else 
      num * fun2(num-1)
	}
 print(fun2(5))

3.包含参数默认值的函数

   /**
     * 包含默认参数值的函数
     */
    def fun3(a :Int = 10,b:Int) = {
      println(a+b)
    }
    fun3(b=2)

1.默认值的函数中,如果传入的参数个数与函数定义相同,则传入的数值会覆盖默认值 2.如果不想覆盖默认值,传入的参数个数小于定义的函数的参数,则需要指定参数名称

4.可变参数个数的函数 用逗号隔开

   /**
     * 包含默认参数值的函数
     */
    def fun3(a :Int = 10,b:Int) = {
      println(a+b)
    }
    fun3(b=2)

5.匿名函数 匿名函数不能显式声明函数的返回类型

    /**
     * 匿名函数
     * 注意:
     * 可以将匿名函数返回给定义的一个变量
     */
    //有参数匿名函数
    val value1 = (a : Int) => {
      println(a)
    }
    value1(1)
    //无参数匿名函数
    val value2 = ()=>{
      println("我爱Angelababy")
    }
    value2()
    //有返回值的匿名函数
    val value3 = (a:Int,b:Int) =>{
      a+b
    }
    println(value3(4,4)) 

6.嵌套函数

    /**
     * 嵌套函数
     * 例如:嵌套函数求5的阶乘
     */
    def fun5(num:Int)={
      def fun6(a:Int,b:Int):Int={
        if(a == 1){
          b
        }else{
          fun6(a-1,a*b)
        }
      }
      fun6(num,1)
    }
    println(fun5(5))

7.偏应用函数 偏应用函数是一种表达式,不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。

    /**
     * 偏应用函数
     */
    def log(date :Date, s :String)= {
      println("date is "+ date +",log is "+ s)
    }
    
    val date = new Date()
    log(date ,"log1")
    log(date ,"log2")
    log(date ,"log3")
    
    //想要调用log,以上变化的是第二个参数,可以用偏应用函数处理
    val logWithDate = log(date,_:String)
    logWithDate("log11")
    logWithDate("log22")
    logWithDate("log33")

8.高阶函数 函数的参数是函数,或者函数的返回类型是函数,或者函数的参数和函数的返回类型是函数的函数。

函数的参数是函数 函数的返回时函数 函数的参数和返回都是函数

/**
 * 高阶函数
 */
//函数的参数是函数
def hightFun(f : (Int,Int) =>Int, a:Int ) : Int = {
  f(a,100)
}
def f(v1 :Int,v2: Int):Int  = {
  v1+v2
}
println(hightFun(f, 1))
//函数的返回是函数
//1,2,3,4相加
def hightFun2(a : Int,b:Int) : (Int,Int)=>Int = {
  def f2 (v1: Int,v2:Int) :Int = {
    v1+v2+a+b
  }
  f2
}
println(hightFun2(1,2)(3,4))
//函数的参数是函数,函数的返回是函数
def hightFun3(f : (Int ,Int) => Int) : (Int,Int) => Int = {
  f
} 
println(hightFun3(f)(100,200))
println(hightFun3((a,b) =>{a+b})(200,200))
//以上这句话还可以写成这样
//如果函数的参数在方法体中只使用了一次 那么可以写成_表示
println(hightFun3(_+_)(200,200))

9.柯里化函数 可以理解为高阶函数的简化

   /**
     * 柯里化函数
     */
    def fun7(a :Int,b:Int)(c:Int,d:Int) = {
      a+b+c+d
    }
    println(fun7(1,2)(3,4))

字符串 1.String 2.StringBuilder 可变长度

    /**
     * String && StringBuilder
     */
    val str = "abcd"
    val str1 = "ABCD"
    
    println(str.indexOf(97))
    println(str.indexOf("b"))

    println(str==str1)
    /**
     * compareToIgnoreCase
     * 
     * 如果参数字符串等于此字符串,则返回值 0;
     * 如果此字符串小于字符串参数,则返回一个小于 0 的值;
     * 如果此字符串大于字符串参数,则返回一个大于 0 的值。
     * 
     */
    println(str.compareToIgnoreCase(str1))
    
    val strBuilder = new StringBuilder
    strBuilder.append("abc")
//    strBuilder.+('d')
    strBuilder+ 'd'
//    strBuilder.++=("efg")
    strBuilder++= "efg" 
//    strBuilder.+=('h')
    strBuilder+= 'h' 
    strBuilder.append(1.0)
    strBuilder.append(18f)
    println(strBuilder)

集合 1.数组 1.创建数组

   /**
     * 创建数组两种方式:
     * 1.new Array[String](3)
     * 2.直接Array
     */
    //创建类型为Int 长度为3的数组
    val arr1 = new Array[Int](3)
    //创建String 类型的数组,直接赋值
    val arr2 = Array[String]("s100","s200","s300")
    //赋值
    arr1(0) = 100
    arr1(1) = 200
    arr1(2) = 300

2.遍历数组

    /**
     * 遍历两种方式
     */
    for(i <- arr1){
    	  println(i)
    }
    arr1.foreach(i => {
      println(i)
    })
    for(s <- arr2){
      println(s)
    }
    arr2.foreach { 
      x => println(x) 
    }

3.二维数组

/**
 * 创建二维数组和遍历
 */
val arr3 = new Array[Array[String]](3)
arr3(0)=Array("1","2","3")
arr3(1)=Array("4","5","6")
arr3(2)=Array("7","8","9")
for(i <- 0 until arr3.length){
  for(j <- 0 until arr3(i).length){
    print(arr3(i)(j)+"	")
  }
  println()
}

var count = 0
for(arr <- arr3 ;i <- arr){
  if(count%3 == 0){
    println()
  }
  print(i+"	")
  count +=1 
}

arr3.foreach { arr  => {
  arr.foreach { println }
}}

val arr4 = Array[Array[Int]](Array(1,2,3),Array(4,5,6))
arr4.foreach { arr => {
  arr.foreach(i => {
    println(i)
  })
}}
println("-------")
for(arr <- arr4;i <- arr){
  println(i)
} **2.List**
    //创建
    val list = List(1,2,3,4,5)
    
    //遍历
    list.foreach { x => println(x)}
//    list.foreach { println}
	/**
	 * list方法
	 */
    //filter
    val list1  = list.filter { x => x>3 }
    list1.foreach { println}
    
    //count
    val value = list1.count { x => x>3 }
    println(value)
    
    //map
    val nameList = List(
    		"hello bjsxt",
    		"hello xasxt",
    		"hello shsxt"
        )
    val mapResult:List[Array[String]] = nameList.map{ x => x.split(" ") }
    mapResult.foreach{println}    
    
    //flatmap
    val flatMapResult : List[String] = nameList.flatMap{ x => x.split(" ") }
    flatMapResult.foreach { println }

3.Set

//创建 
val set1 = Set(1,2,3,4,4)
val set2 = Set(1,2,5)
//遍历
//注意:set会自动去重
set1.foreach { println}
   for(s <- set1){
      println(s)
    }
    println("*******")

   /**
    * Set方法举例
    */    
   //交集
   val set3 = set1.intersect(set2)
   set3.foreach{println}
   val set4 = set1.&(set2)
   set4.foreach{println}
   println("*******")
   //差集
   set1.diff(set2).foreach { println }
   set1.&~(set2).foreach { println }
   //子集
   set1.subsetOf(set2)
   //最大值
   println(set1.max)
   //最小值
   println(set1.min)
   println("****")
   //转成数组,list
   set1.toArray.foreach{println}
   println("****")
   set1.toList.foreach{println}
   //mkString
   println(set1.mkString)
   println(set1.mkString("\t"))

4.Map 1.Map创建

val map = Map(
  "1" -> "bjsxt",
  2 -> "shsxt",
  (3,"xasxt")
)

注意 :创建map时,相同key被后面的相同的key顶替掉,只保留一个 2.获取值

println(map.get("1").get)
// getOrElse:如果map中没有对应项,赋值为getOrElse传的值
val result = map.get(8).getOrElse("no value")
println(result)

3.Map遍历

//遍历key
val keyIterable = map.keys
keyIterable.foreach { key => {
  println("key:"+key+", value:"+map.get(key).get)
} }
println("---------")

4.key遍历

//遍历key
val keyIterable = map.keys
keyIterable.foreach { key => {
  println("key:"+key+", value:"+map.get(key).get)
} }
println("---------")

5.value遍历

//遍历value
val valueIterable = map.values
valueIterable.foreach { value => {
  println("value: "+ value)
} }

6.map合并

/**
 * 合并map
 * ++   例:map1.++(map2)     map1中加入map2
 * ++:  例:map1.++:(map2)    map2中加入map1
 */
val map1 = Map(
  (1,"a"),    
  (2,"b"),    
  (3,"c")    
)
val map2 = Map(
  (1,"aa"),
  (2,"bb"),
  (2,90),
  (4,22),
  (4,"dd")
)
map1.++:(map2).foreach(println)     

注意:合并map会将map中的相同key的value替换 7.map方法

//count
val countResult  = map.count(p => {
  p._2.equals("shsxt")
})
println(countResult)
//filter
map.filter(_._2.equals("shsxt")).foreach(println)
//contains:map中是否包含某个key
println(map.contains(2))
//exist:符合条件的记录存在不存在
println(map.exists(f =>{
  f._2.equals("Angelababy")
}))

5.元组 1.定义 与列表一样,与列表不同的是元组可以包含不同类型的元素。元组的值是通过将单个的值包含在圆括号中构成的 2.元组创建与取值

/**
 * 创建,最多支持22个
 * 可以使用new,可以不适用new
 */
val tuple = new Tuple1(1)
val tuple2 = Tuple2("zhangsan",2)
val tuple3 = Tuple3(1,2,3)
val tuple4 = (1,2,3,4)
val tuple18 = Tuple18(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)
val tuple22 = new Tuple22(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)

//使用
//取值用"._XX"可以获取元组中的值
println(tuple2._1 + "\t"+tuple2._2)
val t = Tuple2((1,2),("zhangsan","lisi"))
println(t._1._2)

tuple最多支持22个参数

3.元组的遍历 先获取迭代器,然后再遍历

//遍历
val tupleIterator = tuple22.productIterator
while(tupleIterator.hasNext){
  println(tupleIterator.next())
}

4.元组的常用方法

//翻转,只针对二元组
println(tuple2.swap)
//toString
println(tuple3.toString())

Trait 1.概念理解 Scala Trait(特征)相当于Java的接口,实际上它比接口功能强大。可以定义属性和方法的实现。 一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承 Trait(特征)定义的方式与类类似,使用关键字trait

2.例子:trait中带属性带方法实现

trait Read {
  val readType = "Read"
  val gender = "m"
  def read(name:String){
	println(name+" is reading")
  }
}

trait Listen {
  val listenType = "Listen"
  val gender = "m"
  def listen(name:String){
	println(name + " is listenning")
  }
}

class Person() extends Read with Listen{
  override val gender = "f"
}

object test {
  def main(args: Array[String]): Unit = {
    val person = new Person()
    person.read("zhangsan")
    person.listen("lisi")
    println(person.listenType)
    println(person.readType)
    println(person.gender)
    
  }
}

注意: 继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义 trait不可以传参数

3.例子:trait中带方法不实现

object Lesson_Trait2 {
  def main(args: Array[String]): Unit = {
    val p1 = new Point(1,2)
    val p2 = new Point(1,3)
    println(p1.isEqule(p2))
    println(p1.isNotEqule(p2))
  }
}

trait Equle{
  def isEqule(x:Any) :Boolean 
  def isNotEqule(x : Any)  = {
    !isEqule(x)
  }
}

class Point(x:Int, y:Int) extends Equle {
  val xx = x
  val yy = y

  def isEqule(p:Any) = {
    p.isInstanceOf[Point] && p.asInstanceOf[Point].xx==xx
  }
}

模式匹配 match 1.概念理解 模式匹配使用关键字match,一个模式匹配包含了一系列备选项。每个备选项都包含了一个模式及一到多个表达式。箭头符号=>隔开了模式和表达式 2.注意 模式匹配不仅可以匹配值还可以匹配类型 按照从上向下的顺序匹配,如果匹配到则不再往下匹配。如果都匹配不上,会匹配到case_,相当于default match的最外面的”{}”可以去掉看成一个语句

object Lesson_Match {
  def main(args: Array[String]): Unit = {
    val tuple = Tuple6(1,2,3f,4,"abc",55d)
    val tupleIterator = tuple.productIterator
    while(tupleIterator.hasNext){
      matchTest(tupleIterator.next())
    }
  }
  def matchTest(x:Any) ={
    x match {
      case x:Int=> println("type is Int")
      case 1 => println("result is 1")
      case 2 => println("result is 2")
      case 3=> println("result is 3")
      case 4 => println("result is 4")
      case x:String => println("type is String")
//      case x :Double => println("type is Double")
      case _ => println("no match")
    }
  }
}

样例类(case class) 1.概念理解 使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类。实现了类构造参数的getter方法(构造参数默认被声明为val),当构造参数是声明为var类型的,它将帮你实现setter和getter方法。 样例类默认帮你实现了toString,equals,copy和hashCode等方法。 样例类可以new, 也可以不用new;

case class Person1(name:String,age:Int)

object Lesson_CaseClass {
  def main(args: Array[String]): Unit = {
    val p1 = new Person1("zhangsan",10)
    val p2 = Person1("lisi",20)
    val p3 = Person1("wangwu",30)
    
    val list = List(p1,p2,p3)
    list.foreach { x => {
      x match {
        case Person1("zhangsan",10) => println("zhangsan")
        case Person1("lisi",20) => println("lisi")
        case _ => println("no match")
      }
    } }
  }
}

Actor Model 1.概念理解 Actor Model是用来编写并行计算或分布式系统的高层次抽象(类似java中的Thread)让程序员不必为多线程模式下共享锁而烦恼,被用在Erlang 语言上, 高可用性99.9999999 % 一年只有31ms 宕机Actors将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors分享状态,每个Actors有自己的世界观,当需要和其他Actors交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外Actors回复,也不必暂停,每个Actors有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。 2.Actor特征 ActorModel是消息传递模型,基本特征就是消息传递 消息发送是异步的,非阻塞的 消息一旦发送成功,不能修改 Actor之间传递时,自己决定决定去检查消息,而不是一直等待,是异步非阻塞的 3.什么是Akka Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和Scala 的 Actor 模型应用,底层实现就是Actor,Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。 spark1.6版本之前,spark分布式节点之间的消息传递使用的就是Akka,底层也就是actor实现的。1.6之后使用的netty传输。 4.代码示例

case class Message(actor:Actor,msg:Any)

class Actor1 extends Actor{
  def act(){
    while(true){
      receive{
        case  msg :Message => {
          println("i sava msg! = "+ msg.msg)
          
          msg.actor!"i love you too !"
          }
        case msg :String => println(msg)
        case  _ => println("default msg!")
      }
    }
  }
}

class Actor2(actor :Actor) extends Actor{
  actor ! Message(this,"i love you !")
	def act(){
		while(true){
			receive{
  			case msg :String => {
  			  if(msg.equals("i love you too !")){
  			    println(msg)
  			   actor! "could we have a date !"
  			  }
  			}
  			case  _ => println("default msg!")
			}
		}
	}
}

object Lesson_Actor2 {
  def main(args: Array[String]): Unit = {
    val actor1 = new Actor1()
    actor1.start()
    val actor2 = new Actor2(actor1)
    actor2.start()
  }
}

隐式转换系统 隐式转换,在编写程序的时候可以尽量少的去编写代码,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,提高代码质量

1.隐式值

 //========================隐式值==============================
def sayName(implicit name:String) = {
  println("say love to " + name)
}

implicit val name = "fanbingbing"
/**
 * not enough arguments for method sayName: (implicit name: String)Unit. Unspecified value parameter name.
 */

/**
 * ambiguous implicit values: both value a of type String and value name of type String match expected type String
 * 隐式转换必须满足无歧义规则
 * 在同一个作用域禁止声明两个类型一致的变量,防止在搜索的时候会犹豫不决
 * 声明隐式参数的类型最好是自定义的数据类型,不要使用Int,String这些常用类型,防止碰巧冲突
 */
//    implicit val a = "hhh"
sayName
/**
 * 将name变量声明为implicit,编译器在执行sayName方法时发现缺少一个String类型的参数,此时会搜索作用域内类型为String的隐式值
		 并且将搜索到的隐式值作为sayName的参数值
 */

2.隐式视图 隐式转换为目标类型:把一种类型自动转换到另一种类型

//========================隐式视图  隐式转换为目标类型:把一种类型自动转换到另一种类型============================== 
 	def addNum(num:Int) = {
      num + 1000
    }
    implicit def stringToInt(num:String) = Integer.parseInt(num)
    //type mismatch; found : String("1000") required: Int
    println(addNum("1000")) 
//========================隐式视图  通过隐式转换,能调用类中本不存在的方法==============================
    implicit def fJJtoXTT(f:FJJ) = new XTT
    //value jpContent is not a member of com.bjsxt.scala.FJJ
    val fjj = new FJJ()
	fjj.jpContent()
	class FJJ{
	}
	class XTT{
	  def jpContent() = {
	    println("nengdaiwochifanjiuhaole")
	  }
	}

3.隐式类 1.注意 (1)其所带的构造参数有且只能有一个 (2)隐式类必须被定义在类,伴生对象和包对象里 (3)隐式类不能是case class(case class在定义会自动生成伴生对象与2矛盾) (4)作用域内不能有与之相同名称的标示符

object Util{
	implicit class StringLength(val s: String){
		def getLength() = s.length
	}
}

import com.hpe.scala.Util.StringLength
println("abc".getLength())

方法调用流程: 编译器在abc对象调用getLength时发现对象上并没有getLength方法,此时编译器就会在作用域范围内搜索隐式实体,发现有符合的隐式类可以用来转换成带有getLength方法的util类,最终调用getLength方法

参考文档

官网
http://www.scala-lang.org/download/
Scala学习笔记
https://www.jianshu.com/p/c16e0fae6ea2

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦