Fork me on GitHub

Scala Day01

Scala Day01


scala的简介

将来的技术发展趋势:stream + ui + sql

怎么设计一门编程语言?

根据已有的东西,提炼共同的思想,并加入新的特性;

设计数据库:

  1. mysql
  2. 查找算法
    key-value
    二分查找
    布隆过滤器
  3. 分布式:分而治之

设计编程语言:

  1. 流程控制 if for while

  2. 操作运算 + - / * % >> << & | ^

  3. 变量定义
    java:String s = "s"
    javascript: var s1 = "s"
    linux shell:s2 = "s"
    一定都是在内存中申请一定的容量来存储"s"这个字符串

  4. 编程规范(换行/缩进,分号,注释,关键字,....)
    java python

  5. 其他范式:
    FP(funntional programming): 函数式的编程语言
    OOP(object orainted programming):面向对象的编程语言(面向切面编程AOP: aspect):一切皆对象,抽象能力

为什么要学习scala这个编程语言?

两方面的原因

  1. 外部原因:spark,
  2. 内部原因:这个scala编程语言自身的原因
    “If I were to pick a language to use today other than Java, it would be Scala.” -- James Gosling

scala的作者 martin odersky;java的泛型特性的作者;

scala 的特点

scala与java很像;它们都是基于JVM的编程语言;基于JVM的语言有很多例如:scala kotlin java .....;

scalac === javac
scala === java

java编程语言的使用:

  1. 文件名:HelloWorld.java
  2. 编译:javac HelloWorld.java
  3. 执行的代码文件:HelloWorld.class
  4. 运行:java HelloWorld

scala编程语言的使用:

  1. 文件名:HelloWorld.scala
  2. 编译:scalac HelloWorld.scala
  3. 执行的代码文件:HelloWorld.class
  4. 运行:scala HelloWorld

object HelloWorld1 {
  def main(args: Array[String]): Unit = {
    println("hello world!")
  }
}

scala的特点:
使用java编程语言。或者在java项目中,定义的类型和对象等等,在scala中都可以使用;

  1. 各种java的类型,jar包等等,在scala当中都可以用。
  2. 只要符合scala的编程语言规范/语法

计算方式

  1. mapreduce 只能做离线批处理(出现早,运行稳定,用户量还可以)
  2. storm 只能做实时流式处理
  3. spark 能做批处理和流式处理(基于批处理设计的)
    spark把流式处理看做是批处理的一种特例
  4. flink 能做批处理和流式处理(基于流式处理设计的)
    flink把批处理看做是流式处理的一种特例

开发和运行环境

  1. DK
    java:JDK
    scala:sdk
  2. IDE
    java:netbean,eclipse,IDEA
    scala:eclipse,IDEA
    python:pycharm
    html:webstorm

关于编译器/解释器的安装

直接在官网上下载,windows可以直接下载msi的程序,mac os或者linux可以下载tar.gz的二进制文件,解压后配置环境变量即可使用;

建议使用IDEA;来编写Scala;

scala和java的区别:

scala和java的区别:

  1. 文件名称
    java:HelloWorld.java public class HelloWorld
    scala:HelloWorld.scala object Test11

  2. 关于main方法
    scala: def main(args: Array[String]) : Unit = {}
    分号:对于scala程序员来说,分号可有可无;

注意:

  1. 在scala中如果要创建一个带有main的方法的类;那么必须创建object类型的文件
  2. scala每一条语句都有返回值;
  3. 如果代码段是一个大括号,那么返回值就是大括号内最后一条语句的返回值;没有返回值的话,返回值的类型就是Unit这个类;

变量的定义

  1. 数据类型可以指定,也可以不指定,如果不指定,那么就会进行数据类型的自动推断。
  2. 如果指定数据类型,数据类型的执行方式是在变量名后面写一个冒号,然后写上数据类型。
  3. scala 里面变量的修饰符一共有两个,一个是 var,一个是 val
    1. var 修饰变量,那么这个变量的值是可以修改的
    2. val 修饰变量,那么这个变量的值是不可以修改的

var

//使用 var 定义的变量值是可变的
var i = 1
//使用 var 定义的变量是可变得,但是在 Scala 中鼓励使用 val
var s = "hello"
//Scala 编译器会自动推断变量的类型,必要的时候可以指定类型
//变量名在前,类型在后
var str: String = "spark"

val

//使用 val 定义的变量值是不可变的,相当于 java 里用 final 修饰的变量
 val i = 3
 //Scala 编译器会自动推断变量的类型,必要的时候可以指定类型
 //变量名在前,类型在后
 val str: String = "spark"

lazy

lazy只能和val一起使用;
lazy表示延迟执行的意思;

// 保存的是内存地址,只有当调用时才会执行
scala> lazy val ss = 3 + 2
ss: Int = <lazy>

scala> println(ss)
5

数据类型

scala数据类型

默认 T型
0 Int 或其子范围类型之一
0L Long
0.0f Float
0.0d Double
false Boolean
() Unit
null 所有其他类型
val var_float = 2.4F
val var_char='A'

WeChat1bb6217218688dbe3fd562736279bbd5

  1. Any 是所有类的父类,包括值类型 AnyVal,和引用类型 AnyRef
  2. AnyVal 是所有值类型的父类,包括 Int,Double,Boolean,Unit 等等
  3. AnyRef 是所有引用类型的父类,包括 Null
  4. Null 是所有引用类型的子类
  5. Nothing 是所有类的子类
  6. Unit 类型只有一个实例,是(),相当于 java 中的 void,没有任何的实质意义
  7. Null 也只有一个实例,是 null,相当于 java 中的 null,能赋值给任何引用类型变量,不能赋值给值类型变量

Scala 基本类型操作

  1. 算术操作:+ - * / % //
  2. 关系运算:> >= < <= == !=
  3. 逻辑运算:&& || !
  4. 位运算: & | ^ ~ >> << >>>
  5. 对象比较:1==1 1==1.0 "huangbo" == "huangbo" ne eq

特别注意:ne eq equals ==

  1. equals== 都是比较值的
  2. eq 比较的是地址
  3. ne 表示不等,比较的也是地址
object HelloWorld1 {
  def main(args: Array[String]): Unit = {
    val s1 = Student(1,"aa")
    val s2 = Student(1,"aa")
    println(s1.equals(s2))
    println(s1 == s2)
    println(s1 eq s2)
    println(s1 ne s2)
  }

  case class Student(i: Int, str: String)

运行结果

true
true
false
true

编码规范

  1. 分号:可有可无,没有实际意义
  2. 注释:注释方式和java是一样的
  3. 关键字:yield, match, object, def, implicit, trait, sealed, var/val
    scala关键字
abstract    case        catch       class       def
do          else        extends     false       final
finally     for         forSome     if          implicit
import      lazy        macro       match       new
null        object      override    package     private
protected   return      sealed      super       this
throw       trait       try         true        type
val         var         while       with        yield
_    :    =    =>    <-    <:    <%     >:    #    @

流程控制

if

package com.aura.scala.day01.first

object IfTest {
  def main(args: Array[String]): Unit = {

    val x = 1
    //判断x的值,将结果赋给y
    val y = if (x > 0) 1 else -1
    //打印y的值
    println(y)
    // 1

    //支持混合类型表达式
    val z = if (x > 1) 1 else "error"
    //打印z的值     println(z)
    // 此时Z的类型是 数值型和 字符串类型 的共同父类;ANY

    //如果缺失else,相当于if (x > 2) 1 else ()
    val m = if (x > 2) 1
    println(m)

    //在scala中每个表达式都有值,scala中有个Unit类,写做(),相当于Java中的void     val n = if (x > 2) 1 else ()     println(n)

    //if和else if     val k = if (x < 0) 0     else if (x >= 1) 1 else -1     println(k)
  }
}
  1. if条件表达式它是有返回值的,返回值是多个分支的返回结果的共同父类
  2. 返回值会根据条件表达式的情况会进行自动的数据类型的推断(返回的是多个分支的共同父类)

for

for 循环语法结构:for (i <- 表达式/数组/集合)
  1. 在 scala 里面没有运算符,都有的符号其实都是方法。

  2. 在 scala 里面没有 ++ -- 的用法

  3. for( i <- 表达式/数组/集合)

  4. 在 for 循环里面我们是可以添加 if 表达式

  5. 有两个特殊表达式需要了解:

    To    1 to 3     1 2 3
    To    1 to (3,2)  1 3
    Until  1 until 3   12
    
  6. 如果在使用 for 循环的时候,for 循环的时候我们需要获取,我们可以是使用 yield 关键字

while

while与java是一样的

object WhileDemo {
  def main(args: Array[String]) {
    var n = 10;
    while (n > 0) {
           println(n)
           n -= 1
    }
  }
}

注意点:在 scala 里面不支持 i++`` i--`` 等操作统一写成 i+=1 i-=1

方法和函数

Scala 中的+ - * / %等操作符的作用与 Java 一样,位操作符 & | ^ >> <<也一样。
只是有一点特别的:这些操作符实际上是方法

定义方法

方法的返回值类型可以不写,编译器可以自动推断出来,但是对于递归函数,必须指定返回类型注意:函数体应该改成叫方法体!!!如果不写等号,代表没有返回值

// 完整格式
def add1(a:Int,b:Int):Int = x+y

scala> def m2(x:Int,y:Int){println("aa")}
m2: (x: Int, y: Int)Unit

方法的定义:与java的方法类似;只是方法的返回值是在 参数后面定义的;

定义函数

// 完整格式
scala> val add2: ((Int, Int) => Int) = (a:Int, b:Int) => a + b
add2: (Int, Int) => Int = <function2>

scala> val dd = (x:Int,y:Int)=> x+y
dd: (Int, Int) => Int = <function2>

经过 scala 的自动类型推断得知,最后返回的结果数据的类型也是 Int。
Function2 中 2 表示这个函数接收的参数个数是 2 个。

val : 用来申明一个函数
add2 : 函数的名称
: : 用来分割函数的名称和类型
((Int, Int) => Int) : 函数的类型 输入两个Int转换成一个Int
= : 是用来定义具体的函数执行逻辑的

(a:Int, b:Int) => a + b : 函数的完整定义
(a:Int, b:Int) : 函数的参数列表
=> 转换操作符 => <- <: <%
{a+b} 函数的具体执行逻辑

将函数当成参数调用

scala> def ceshi(x:Int, y:Int, func1:((Int, Int) => Int)) = func1(x, y)
ceshi: (x: Int, y: Int, func1: (Int, Int) => Int)Int

scala> def max(x:Int, y:Int):Int = if(x>y)x else y
max: (x: Int, y: Int)Int

scala> def add(x:Int, y:Int):Int = x + y
add: (x: Int, y: Int)Int

scala> ceshi(3, 4, max)
res44: Int = 4

scala> ceshi(3, 4, add)
res45: Int = 7

原来:

定义逻辑(ceshi), 定义输入(数据x, y), 调用方法, 得到输出
定义逻辑(ceshi), 传入输入(逻辑max, add), 调用方法, 得到输出

方法和函数的区别

  1. 函数可以作为参数传递给方法,也就是说函数可以作为方法的参数在函数式编程语言中,函数是“头等公民”,它可以像任何其他数据类型一样被传递和操作案例:首先定义一个方法,再定义一个函数,然后将函数传递到方法里面
    函数与方法的区别1

  2. 函数可以作为方法的参数,但是也可以作为函数的参数
    函数与方法的区别2

  3. 方法也可以作为方法的参数。在需要传入函数作为参数的位置上传入一个方法的话,那么这个方法会被自动的转换为函数作为参数,也可以通过_把方法转换为参数
    函数与方法的区别3

  4. 方法也可以作为函数的参数。其实,原理就是方法会被自动转换为函数,所以也就是传入一个函数到一个函数作为参数。

    scala> def m1(x:Int,y:Int)=x+y
    m1: (x: Int, y: Int)Int
    
    scala> val f2 = (f:(Int,Int)=>Int,z:Int,b:Int) => f(z,b)
    f2: ((Int, Int) => Int, Int, Int) => Int = <function3>
    
    scala> f2(m1,2,3)
    res0: Int = 5
    
    scala> f2(m1 _,2,3)
    res1: Int = 5
    
    scala>
    

将方法转换成函数使用

方法转换为函数

数组

定长数组和变长数组

  1. 由于 Array 是不可变(长度不可变)的,初始化之初就有了固定的长度,所以不能直接地对其元素进行删除操作,也不能多增加元素,只能修改某个位置的元素的值,要实现删除可以通过过滤生成新的 Array 的方式来删除不要的元素。所以也就没有 add,insert,remove 等操作。

  2. 而 ArrayBuffer是可变的,本身提供了很多元素的操作,当然包括增加,删除操作。

  3. 如果你需要在 Array 和 ArrayBuffer 之间转换,那么分别调用 toBuffer()和 toArray()方法即可


object ArrayDemo {

  def main(args: Array[String]) {

    //初始化一个长度为8的定长数组,其所有元素均为0     val arr1 = new Array[Int](8)
    //直接打印定长数组,内容为数组的hashcode值     println(arr1)
    //将数组转换成数组缓冲,就可以看到原数组中的内容了
    //toBuffer会将数组转换长数组缓冲
    println(arr1.toBuffer)

    //注意:如果new,相当于调用了数组的apply方法,直接为数组赋值
    //初始化一个长度为1的定长数组
    val arr2 = Array[Int](10)
    println(arr2.toBuffer)

    //定义一个长度为3的定长数组
    val arr3 = Array("hadoop", "storm", "spark")
    //使用()来访问元素
    println(arr3(2))

    //////////////////////////////////////////////////
    //变长数组(数组缓冲)
    //如果想使用数组缓冲,需要导入import scala.collection.mutable.ArrayBuffer包     val ab = ArrayBuffer[Int]()
    //向数组缓冲的尾部追加一个元素
    //+=尾部追加元素     ab += 1
    //追加多个元素
    ab += (2, 3, 4, 5)
    //追加一个数组++=
    ab ++= Array(6, 7)
    //追加一个数组缓冲
    ab ++= ArrayBuffer(8,9)
    //打印数组缓冲ab

    //在数组某个位置插入元素用insert
    ab.insert(0, -1, 0)
    //删除数组某个位置的元素用remove
    ab.remove(8, 2)
    println(ab)
  }
}

可变和不可变

可变:mutable
不可变:immutable

与val一定要分开;val是指引用不可变;此处的可变不可变指的是内容
不可变的集合 就跟 val修饰的普通值变量一样

遍历数组

三种方式

val arr = Array(1,2,3,4,5,6)
for(i <- arr){
    println(i)
}

for(i <- 0 to arr.length -1){
    println(arr(i))
}

for( i <- 0 until arr.length){
    println(arr(i))
}

until 会生成一个左开右闭的range
to 会生成一个左右全开的range

数组转换

yield 关键字将原始的数组进行转换会产生一个新的数组,原始的数组不变

scala> val arr = Array(1,2,3,4,5,6)
arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)

// 将每个元素都乘以2
scala> var res = for(e <- arr) yield e*2
res: Array[Int] = Array(2, 4, 6, 8, 10, 12)


scala> arr.map(_*2)
res2: Array[Int] = Array(2, 4, 6, 8, 10, 12)

其中还有 redcuce和filter方法


数组的常用算法

sum
count
max
min
avg
count(distinct)

多维数组


scala> var arr2 = Array(Array(1,2,3),Array(2,3,4))
arr2: Array[Array[Int]] = Array(Array(1, 2, 3), Array(2, 3, 4))

scala> arr2(0)(2)
res7: Int = 3

scala> for(i<-arr2)println(i.mkString(","))
1,2,3
2,3,4

集合

Scala 的集合有三大类:序列 Seq、集合 Set、映射 Map,
所有的集合都扩展自 Iterable 特质在 Scala 中集合有可变(mutable)和不可变(immutable)两种类型,immutable 类型的集合初始化后就不能改变了(注意与 val 修饰的变量进行区别)

https://blog.csdn.net/zhongqi2513/article/details/82956813
Scala 中的集合分为两种,一种是可变的集合,另一种是不可变的集合
//可变的集合可以更新或修改,添加、删除、修改元素将作用于原集合
//不可变集合一量被创建,便不能被改变,添加、删除、更新操作返回的是新的集合,老集合保持不变

List

不可变的序列
import scala.collection.immutable._ 在 Scala 中列表要么为空(Nil 表示空列表)要么是一个 head 元素加上一个 tail 列表。
第一个概念:List是由一个头元素 + 一个尾队列组成


val list1 = List(1,2,3,4,5)
head:  1
tail:  2,3,4,5

val list2 = List(2)
head:  2
tail:  Nil

scala> val list1 = List(1,2,3,4,5)
list1: List[Int] = List(1, 2, 3, 4, 5)

// 右优先!!!
scala> val list2 = 1 :: 2 :: 3 :: 4 :: 5 :: Nil
list2: List[Int] = List(1, 2, 3, 4, 5)

val list5 = 3 :: 4 :: 5 :: Nil
val list3 = 2 :: list5
vali list4 = 1 :: list3

注意:
1、如果没有任何元素,这个List就是Nil
2、如果只有一个元素,这个List就是element :: Nil
3、如果有多个元素,这个List: element1 :: List2

lst1 = (1,2,3)
 0 +: lst1  ====>  (0, 1, 2, 3)
 lst1 :+ 4  ====>  (1, 2, 3, 4)

 List list11 = null;
 val list: List = Nil

list的四个属性:head, tail, init , last

scala> val list1 = List(1,2,3,4,5)
list1: List[Int] = List(1, 2, 3, 4, 5)

scala> list1.tail
res3: List[Int] = List(2, 3, 4, 5)

scala> list1.init
res4: List[Int] = List(1, 2, 3, 4)


scala> list1.head
res5: Int = 1

scala> list1.last
res6: Int = 5

序列基本操作

package com.aura.scala.day01.first

object ListTest {
  def main(args: Array[String]): Unit = {
    // 创建一个不可变的集合
    val list1 = List(1, 2, 3)

    // 将0插入到list1的前面生成一个新的List
    val list2 = 0::list1
    val list3 = list1.::(0)
    val list4= 0 +:list1
    val list5 = list1.+:(0)

    // 将一个元素添加到list1的后面产生一个新的集合
    val list6= list1 :+ 4
    val list0 = List(4,5,6)

    // 将2个list合并成一个新的List
    val list7 = list1 ++ list0
    // 将list0插入到list1的前面
    val list8 = list1 ++: list0

    // 将list0插入到list1前面生成一个新的集合
    val list9 = list1.:::(list0)
    print(list9)
  }
}

序列其他操作

scala> val nums = 1 ::(2 ::(3::(4::Nil)))
nums: List[Int] = List(1, 2, 3, 4)

scala> val nums = 1::2::3::4::Nil
nums: List[Int] = List(1, 2, 3, 4)

scala> nums.isEmpty
res9: Boolean = false

// 插入排序算法
scala> def insert(x: Int, xs: List[Int]): List[Int] = if (xs.isEmpty || x <= xs.head) x :: xs else xs.head :: insert(x, xs.tail)
insert: (x: Int, xs: List[Int])List[Int]

scala> def isort(xs:List[Int]):List[Int] = if(xs.isEmpty) Nil else insert(xs.head,isort(xs.tail))
isort: (xs: List[Int])List[Int]

scala>

// List连接操作
scala> List(1,2,3):::List(4,5,6)
res11: List[Int] = List(1, 2, 3, 4, 5, 6)

// List倒置
scala> nums.reverse
res12: List[Int] = List(4, 3, 2, 1)

scala> nums
res13: List[Int] = List(1, 2, 3, 4)

// 丢弃前N个元素

scala> val nums = List(1,2,3,4,5,6,7)
nums: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

scala> nums drop 2
res0: List[Int] = List(3, 4, 5, 6, 7)

scala> nums.drop(2)
res1: List[Int] = List(3, 4, 5, 6, 7)

// 获取前N个元素
scala> nums take 3
res2: List[Int] = List(1, 2, 3)

scala> nums.take(3)
res3: List[Int] = List(1, 2, 3)

// 将列表进行分割,在参数的位置切一刀
scala> nums.splitAt(3)
res4: (List[Int], List[Int]) = (List(1, 2, 3),List(4, 5, 6, 7))

// 拉链
//Zip 操作
scala> val nums=List(1,2,3,4)
nums: List[Int] = List(1, 2, 3, 4)

scala> val chars=List('1','2','3','4')
chars: List[Char] = List(1, 2, 3, 4)

//返回的是 List 类型的元组(Tuple)
scala> nums zip chars
res130: List[(Int, Char)] = List((1,1), (2,2), (3,3), (4,4))

//List toString 方法
scala> nums.toString
res131: String = List(1, 2, 3, 4)

//List mkString 方法
scala> nums.mkString
res132: String = 1234

scala> nums.mkString("-")
res0: String = 1-2-3-4-5-6-7


//转换成数组
scala> nums.toArray
res134: Array[Int] = Array(1, 2, 3, 4)

可变序列

  val lst0 = ListBuffer[Int](1,2,3)
  //创建一个空的可变列表
  val lst1 = new ListBuffer[Int]
  //向lst1中追加元素,注意:没有生成新的集合   lst1 += 4
  lst1.append(5)

  //将lst1中的元素最近到lst0中, 注意:没有生成新的集合   lst0 ++= lst1

  //将lst0和lst1合并成一个新的ListBuffer 注意:生成了一个集合   val lst2= lst0 ++ lst1

  //将元素追加到lst0的后面生成一个新的集合
  val lst3 = lst0 :+ 5
}
posted @ 2019-10-06 15:12  耳_东  阅读(131)  评论(0)    收藏  举报