Scala介绍

Scala介绍

java和scala关系

  • java — JVM
    xxx.java —javac— yyy.class ----- java
    真正在jvm中能够运行的是.class字节码文件
    Scala之父:Martin Odersky 马丁·奥德斯基
  • Scala也是JVM系的语言。
    xxx.scala —scalac ---- yyy.class ---- scala
    scala和java是可以混合编程。
  • scala底层用到的还是java,只是在java上套了一层壳,由于scala最终被编译为.class 所以其实本质上还是java 所以在scala中可以任意的调用java的api

scala的多范式编程

  • Scala将面向对象和函数式编程结合成一种简洁的高级语言。
  • Scala的静态类型有助于避免复杂应用程序中的错误,java也是静态类型的。

静态类型:指的就是类型一旦确定就不能更改

int a = 10;//a是int类型的
a = "java";//error

面向对象编程

  • 面向对象:不断创建对象、使用对象完成功能
  • java不是纯面向对象的。基本数据类型、静态
  • scala是纯面向对象的。一切皆对象。没有基本数据类型

函数式编程

函数式编程:将函数提升成“一等公民”,函数也是对象,函数就可以当作参数和返回值。

Scala下载和安装

下载地址:https://www.scala-lang.org/download/all.html,我安装的是kafka_2.11-1.0.2.tgz

安装的前提条件:

  • 确保安装了JDK8。
  • 安装路径不允许出现中文和特殊字符。
  • 安装完成后配置SCALA_HOME的环境变量

表达式

表达式是可计算的语句。

scala> 1 + 1
res1: Int = 2

数据类型

在Scala中,所有的值都有类型,包括数值和函数。下图 阐述了类型层次结构的一个子集。

在这里插入图片描述

Scala类型层次结构

Any

  • Any是所有类型的超类型,也称为顶级类型。
  • 它定义了一些通用的方法如equals、hashCode和toString。
  • Any有两个直接子类:AnyVal和AnyRef。

AnyVal

  • AnyVal代表值类型。
  • 有9个预定义的非空的值类型分别是:Double、Float、Long、Int、Short、Byte、Char、Unit和Boolean。
  • Unit是不带任何意义的值类型,它仅有一个实例可以像这样声明:()。
  • 所有的函数必须有返回,所以说有时候Unit也是有用的返回类型。

AnyRef

  • AnyRef代表引用类型。
  • Scala中除了AnyVal外,都是AnyRef类型
  • 在Scala中,每个用户自定义的类型都是AnyRef的子类型。如果Scala被应用在Java的运行环境中,AnyRef相当于java.lang.Object。

Nothing

  • Nothing是所有类型的子类型,也称为底部类型。
  • 没有一个值是Nothing类型的。它的用途之一是给出非正常终止的信号,如抛出异常、程序退出或者一个无限循环(可以理解为它是一个不对值进行定义的表达式的类型,或者是一个不能正常返回的方法)。

Null

  • Null是所有引用类型的子类型(即AnyRef的任意子类型)。
  • 它有一个单例值由关键字null所定义。
  • Null主要是使得Scala满足和其他JVM语言的互操作性,但是几乎不应该在Scala代码中使用。

类型转换

在这里插入图片描述

变量和常量

scala中使用var修饰变量;使用val修饰常量

  1. java中定义变量的格式:

    数据类型 变量名;
    
  2. java中变量的初始化:

    	数据类型 变量名 = 初始值;
    或:
        数据类型 变量名;
        变量名 = 初始值;
    
  3. scala中定义变量及初始化

    // 方式一:使用了类型推断
    var 变量名 = 值
    
    scala> var age = 10
    age: Int = 10
    
    // 方式二:显式指定数据类型
    var 变量名:数据类型 = 值
    
    scala> var name:String ="zhangsan"
    name: String = zhangsan
    
    // 方式三:显式指定数据类型
    var 变量名 =:数据类型
    
    scala> var sum = 20:Double
    sum: Double = 20.0
    

    注意:scala语句后面可以不要分号;除非一行上有 多条语句。

  4. scala中定义常量

    常量只能赋值一次。
    格式和变量一样,仅仅是将var变成val即可。

类型推断

scala定义变量的时候可以省略类型,scala编译器可以根据变量的值推断出变量的数据类型。但是在有些情况下类型是不能省略的。

IDEA中编写Scala代码

  1. 在创建的module的main下创建一个scala文件夹

  2. 右键scala – Mark directory as — Source root

  3. 在创建好的module上右键-- add framework support – 勾选scala

    注意:如果没有出现scala sdk,选择create — browse— scala安装目录添加即可。

代码块(Blocks)

用{}包围起来。我们称之为代码块(block)。

代码块中最后一个表达式的结果就是整个代码块的结果。

println({
val x = 1 + 1
x + 1
}) // 3

运算符

scala> var a = 1
a: Int = 1
scala> var b = a + 3
b: Int = 4
scala> var b = a.+(3)
b: Int = 4

在scala中一切皆对象,所以上面代码中的1是对象,a也 是对象。按照我们面向对象的知识,对象访问的是属性或方法。

所以,在scala中的运算符(=除外)其实是方法。

  • *运算符

    var name:String = "java"
    println(name * 2) // javajava
    
  • scala中没有++和–

  • ==

    var s1:String = new String("java")
    var s2:String = new String("java")
    println(s1 == s2) //true
    println(s1.equals(s2)) //true
    
  • +=、-=

    var a:Byte = 2
    a += 3
    println(a) //error
    //scala中+=等符号没有做类型转换
    

流程控制

if语句

在scala中if语句是有返回值的。
返回值就是if代码块最后一条语句的结果
注意: scala中没有switch语句。但是提供了比switch更加强大的模式匹配。

for循环

scala> 1 to 10
res4: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> 1 until 10
res7: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
  • 循环输出1-10的所有数

    //循环输出1-10的所有数
    for(i <- 1 to 10){
    	println(i)
    }
    println("-------------------")
    
    //循环输出10 - 1的所有数
    for(i <- 10.to(1,-1) ){
    	println(i)
    }
    
for循环守卫
//这里的if叫做for循环的守卫
for (i <- 1 to 10 if(i % 2 == 0)){
	println(i)
}
for…yield

作用:就是遍历每一个元素,执行yield中的逻辑,将得到的结果存在集合中

//得到1-10的所有数乘以2的结果
/**
* for...yield
* 作用:就是遍历每一个元素,执行yield中的逻辑,将得到的结果存在集合中
*/
val ints: immutable.IndexedSeq[Int] = for (i <- 1 to 10) yield i * 2
for循环嵌套
for(i <- 1 to 9;j <- 1 to i){
print(j + "*" + i + "=" + (i * j) +"\t")
    if(i == j){
    	println()
    }
}
while循环
def main(args: Array[String]): Unit = {
    //循环输出1-10的数字
    var i = 1
    while(i <= 10){
        println(i)
        i+=1
    }
}
do…while循环
def main(args: Array[String]): Unit = {
    //循环输出1-10的数字
    var i = 1
    do {
        println(i)
        i+=1
    }while(i <= 10)
}
循环中断

scala中没有break、continue关键字

  • scala实现java中break的效果:

    def main(args: Array[String]): Unit = {
        //循环输出1-10
        //当数据等于5的时候中断循环
        val loop = new Breaks()
        loop.breakable{ //捕获异常
            for(i <- 1 to 10){
                if( i == 5) {
                    loop.break() //抛出异常
                }
                println(i)
            }
        }
    }
    
  • scala实现java中continue的效果:

    //使用for循环守卫
    for(i <- 1 to 10 if(i != 5)){
    	println(i)
    }
    

    也可以用break实现

    def main(args: Array[String]): Unit = {
        //循环输出1-10
        //当数据等于5的时候中断循环
        val loop = new Breaks()
        for(i <- 1 to 10){
            loop.breakable{ //捕获异常
                if( i == 5) {
                    loop.break() //抛出异常
                }
                println(i)
            }
        }
    }
    

方法

在Java中方法和函数一回事。但是在scala中方法是方 法,函数是函数,方法和函数有区别。

  • scala中方法使用def定义
  • scala中方法是类的一部分
  • scala中函数使用val修饰
  • scala中函数是对象

格式

def 方法名(参数名:参数类型):返回值类型={
方法体
}

// 入口
def main(args: Array[String]): Unit = {}
//定义一个方法,输出hello, scala
/**
* :返回值数据类型 省略,scala使用类型推断
* 递归方法不能省略 :返回值数据类型
*
* :返回值数据类型= 返回值类型就是Unit
*/
def m01() = {
	println("hello, scala")
}

Scala支持方法重载
Scala方法可以嵌套
Scala无参方法调用的时候可以省略()

def main(args: Array[String]): Unit = {
    println(add(2,3))
    def add(a:Int,b:Int):Int={
    	a + b
    }
}

可变参数

参数名:数据类型 *
def main(args: Array[String]): Unit = {
    //:_* 得到集合中的所有元素
    val sum = add(1 to 10 :_*)
    println(sum)
}

//可变参数
def add(a:Int *):Int={
    var sum = 0
    for(i <- a){
    	sum += i
    }
    sum
}

字符串插值器

https://docs.scala-lang.org/zh-cn/overviews/core/string-interpolation.html
自2.10.0版本开始,Scala提供了一种新的机制来根据数据生成字符串:字符串插值。字符串插值允许使用者将变量引用直接插入处理过的字面字符中。

val name="James"
println(s"Hello,$name")//Hello,James

Scala 提供了三种创新的字符串插值方法:s,f 和 raw.

s 字符串插值器

在任何字符串前加上s,就可以直接在串中使用变量了

字符串插值器也可以处理任意的表达式。例如:

println(s"1+1=${1+1}") 将会输出字符串1+1=2。任何表达式都可以嵌入到${}中。

f 插值器

在任何字符串字面前加上 f,就可以生成简单的格式化串,功能相似于其他语言中的 printf 函数。当使用 f 插值器的时候,所有的变量引用都应当后跟一个printfstyle格式的字符串,如%d。

val height=1.9d
val name="James"
println(f"$name%s is $height%2.2f meters tall")//James is 1.90 meters tall f 插值器是类型安全的。如果试图向只支持 int 的格式化串传入一个double 值,编译器则会报错。例如:

val height:Double=1.9d

scala>f"$height%4d"
<console>:9: error: type mismatch;
 found : Double
 required: Int
           f"$height%4d"
              ^ f 插值器利用了java中的字符串数据格式。这种以%开头的格式在 [Formatter javadoc] 中有相关概述。如果在具体变量后没有%,则格式化程序默认使用 %s(串型)格式。

raw 插值器

除了对字面值中的字符不做编码外,raw 插值器与 s 插值器在功能上是相同的。如下是个被处理过的字符串:

scala>s"a\nb"
res0:String=
a
b //这里,s 插值器用回车代替了\n。而raw插值器却不会如此处理。
scala>raw"a\nb"
res1:String=a\nb 当不想输入\n被转换为回车的时候,raw 插值器是非常实用的。

默认参数值

Scala具备给参数提供默认值的能力,这样调用者就可以忽略这些具有默认值的参数。

def log(message: String, level: String = "INFO") = println(s"$level: $message")

log("System starting")  // prints INFO: System starting
log("User not found", "WARNING")  // prints WARNING: User not found

命名参数

  • 当调用方法时,实际参数可以通过其对应的形式参数的名称来标记:
  • 注意使用命名参数时,顺序是可以重新排列的。 但是,如果某些参数被命名了,而其他参数没有,则未命名的参数要按照其方法签名中的参数顺序放在前面。
  • 注意调用 Java 方法时不能使用命名参数。
def printName(first: String, last: String): Unit = {
  println(first + " " + last)
}

printName("John", "Smith")  // Prints "John Smith"
printName(first = "John", last = "Smith")  // Prints "John Smith"
printName(last = "Smith", first = "John")  // Prints "John Smith"
def main(args: Array[String]): Unit = {
    m03(age=20, name="zhangsan",sex="male")
    m03( "zhangsan",age=20,"male")
}

def m03(name:String,age:Int,sex:String)={
	println(s"$name,$age,$sex")
}

函数

Scala中函数也是对象。

Scala中的函数是继承了Function0—Function22特质的对象

函数定义

// ()=>函数体
scala> ()=>println("scala") //匿名函数,无参,返回值是Unit
res10: () => Unit = <function0> // 函数的数据类型
// () => Unit 该函数具体的数据类型
//function0 该函数具体数据类型的特质
def main(args: Array[String]): Unit = {
    //val age = 10
    val f01 = () => println("hello")
    //val age:Int = 10
    val f02:()=>Unit = () => println("hello")
    //val age = 10:Int
    val f03 = (() => println("hello")):()=>Unit
    f01 //获取的是函数的信息
    f01()//调用函数
}

注意:
1、无参方法调用的时候可以省略()
2、无参函数调用的时候不能省略()

def main(args: Array[String]): Unit = {
    val f01 = (s:String) => println(s)
    // val f02 = (a:Int,b:Int) => a + b
    // val f02:(Int,Int)=>Int = (a:Int,b:Int) => a + b
    // val f02:(Int,Int)=>Int = (a,b) => a + b
    //如果函数参数在函数体中只使用了一次,可以使用_替换(暂时这么记忆,这个不完全正确)
    val f02:(Int,Int)=>Int = _ + _
    
    //val f02 = _ + 2
    // val f02:Int=>Int = _+2
    // val f02:Function2[Int,Int,Int] = (a,b) => a + b
    println(f02)
    println(f02(1,2))
}

函数作为参数

/**
* 定义一个方法实现两个Int数据的任意运算
* 也就是说这个方法既可以做加法、也可以减法、乘法等其他运算
*
* 分析:
* 1、参数的定义
* 接收任意两个Int数据的参数:a,b
* 这个方法需要满足做任意运算,那么在定义方
法的时候需要定义一个参数来接收任意的运算
* 运算不是单一的值,而是一个表达式。在Java中运算都是定义方法
* 在Scala中运算可以是方法、可以是函数
* 所以在这个需要作为参数传递,我们定义一个参数接收函数
*/
object FunctionDemo02 {
    def main(args: Array[String]): Unit ={
        // val f = (a:Int,b:Int)=>a + b
        // println(m01(1,2,f))
        // println(m01(1,2,(a:Int,b:Int)=>a + b))
        // println(m01(1,2,(a,b)=>a + b))
        println(m01(1,2,_+_))
        println(m01(1,2,_-_))
        println(m01(1,2,_*_))
        println(m01(1,2,_/_))
        println(m01(1,2,_%_))
        }
    
    def m01(a:Int,b:Int,f:(Int,Int)=>Int):Int ={
        f(a,b)
    }
}

方法转函数

object FunctionDemo04 {
    def main(args: Array[String]): Unit = {
        //add方法 自动转成了函数
        println( m01(1,2,add))
        //add方法 手动转函数
        // println( m01(1,2,add _))
        val f01:(Int,Int)=>Int = add
        println(m01(2,3,f01))
    }
    
    def m01(a:Int,b:Int,f:(Int,Int)=>Int):Int ={
 		f(a,b)
    }
    def add(a:Int,b:Int):Int={
    	a + b
    }
}

函数作为返回值

package com.bigdata.scala02
object FunctionDemo05 {
    def main(args: Array[String]): Unit ={
        // val f = m01
        // val f = m01()
        // println(f(1,2))
        // val f01 = m02(1,2)
        // (Int,Int) => ()=>Int
        val f01:(Int,Int) =>()=>Int = m02
        println(f01(1,2)())
        // val f01:()=>Int = m02(1,2)
        // println(f01())
    }
    
    def m01():(Int,Int)=>Int ={
    	_ + _
    }
    
    def m02(a:Int,b:Int):()=>Int ={
        val f:()=>Int = ()=> a + b
        f
    }
}

惰性变量

被lazy修饰的val变量就是惰性变量。

比如数据库的连接就可以使用惰性变量。

//懒加载
object LazyVarDemo {
	def main(args: Array[String]): Unit ={
        lazy val num = m01()
        println(num)
    }
    
    def m01():Int={
        println("m01------------")
        10
    }
}

type

在scala中可以使用type给类、特质取别名

type String = java.lang.String

type xx = Int //取别名
var num:xx = 20

神奇的下划线_

  1. :_* 获取集合一个一个的元素_

    package com.bigdata.scala01
    
    object MethodDemo02 {
    
      def main(args: Array[String]): Unit = {
        //:_* 得到集合中的所有元素
        val sum = add(1 to 10 :_*)
        println(sum)
      }
    
      //可变参数
      def add(a:Int *):Int={
       var sum = 0
        for(i <- a){
          sum += i
        }
        sum
      }
    }
    
  2. _如果函数参数在函数体中只使用了一次,可以使用_替换

  3. 方法转函数: 方法名 _

    package com.bigdata.scala02
    
    /**
     * 定义一个方法实现两个Int数据的任意运算
     *   也就是说这个方法既可以做加法、也可以减法、乘法等其他运算
     *
     *   分析:
     *   1、参数的定义
     *      接收任意两个Int数据的参数:a,b
     *     这个方法需要满足做任意运算,那么在定义方法的时候需要定义一个参数来接收任意的运算
     *     运算不是单一的值,而是一个表达式。在Java中运算都是定义方法
     *     在Scala中运算可以是方法、可以是函数
     *     所以在这个需要作为参数传递,我们定义一个参数接收函数
     *
     *
     */
    object FunctionDemo04 {
    
      def main(args: Array[String]): Unit = {
        //add方法 自动转成了函数
       println( m01(1,2,add))
    
        //add方法 手动转函数
    //   println( m01(1,2,add _))
    
        val f01:(Int,Int)=>Int = add
        println(m01(2,3,f01))
      }
    
      def m01(a:Int,b:Int,f:(Int,Int)=>Int):Int ={
        f(a,b)
      }
    
      def add(a:Int,b:Int):Int={
        a + b
      }
    }
    
  4. 成员变量初始化的时候作为占位符

    class Student {
      //成员变量
      var name:String = _
      var age:Int = _
      var sex:String = _
    
    }
    
  5. 导入包下所有的内容,使用_

    // _相当于Java中的*,scala可以导入类的属性和方法
    import com.bigdata.demo01._
    

_的注意事项

def main(args: Array[String]): Unit = {
    // val f01:(Int,Int)=>Unit = (a,b)=>println(a + b)
    //_单独使用就是一个值,不作为表达式
    //_运算的时候是需要进行函数展开的,遇见()也会进行函数展开
    val f01:(Int,Int)=>Int = _ + _ + 3
    // _ + _ + 3 == (a:Int,b:Int)=>a + b + 3
    //(_ + _) + 3 == ((a:Int,b:Int)=>a + b) + 3
    println(f01(1,2))
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值