Skip to content

函数式编程之基础

1. 面向函数式编程概述

1.1 面向对象编程

解决问题,分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题。
Scala语言是一个完全面向对象编程语言。所谓万物皆对象。
对象的本质:对数据和行为的一个封装。
比如对象:用户;行为:登录、连接JDBC、读取数据库;属性:用户名、密码。

1.2 面向函数式编程

解决问题时,将问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用这些封装好的步骤,解决问题。
Scala 语言是一个完全函数式编程语言。万物皆函数。
函数的本质:函数可以当做一个值进行传递。对功能的封装。
在Scala中函数式编程和面向对象编程完美融合在一起了。
比如:请求->用户名、密码->连接 JDBC->读取数据库

1.3 Scala函数和Java方法的区别

  1. 称呼不同:Java中功能的封装是方法,Scala中称为函数。
  2. 只有在Java类中才能声明方法; 函数可以在任何地方声明,不受到限制。
  3. 函数没有重载和重写的概念;Java方法可以进行重载和重写。
  4. Scala中函数可以嵌套定义函数,而Java方法不能。
scala
def main(args: Array[String]): Unit = {
    // (1)Scala 语言可以在任何的语法结构中声明任何语法
    import java.util.Date
    new Date()
    // (2)函数没有重载和重写的概念,程序报错
    def test(): Unit ={
        println("无参,无返回值")
    }
    test()
    def test(name:String):Unit={
        println()
    }
    //(3)Scala 中函数可以嵌套定义
    def test2(): Unit ={
        def test3(name:String):Unit={
            println("函数可以嵌套定义")
        }
    }
}

3. 函数基础

3.1 函数基本语法

基本语法:
Alt text

3.2 Scala函数和Scala方法的区别

Alt text Scala中存在函数和方法两个概念,区别比较小:

  1. Scala函数和Scala方法的声明位置不同,Scala方法声明在类中,Scala函数声明在Scala方法中。
  2. Scala方法可以通过对象.方法调用,Scala函数直接调用。
  3. Scala函数是一个对象,可以赋值给其他变量,而Scala方法是组成类中一部分。
  4. Scala中函数可以嵌套定义。Scala方法就是在类中的成员,不能定义在其他位置。
  5. Scala方法可以重载,和Java方法类似。
scala
object FunctionDemo {

    def main(args: Array[String]): Unit = {
        // 函数可以嵌套定义
        def test(): Unit = {
            println("test function.....")
        }
        // 如果方法和函数名称相同,优先调用函数,调用方法需要对象.test()指明
        test()
         this.test()
        // 如果函数参数没有可以简写函数名
        test
    }

    def test():Unit={
        println("test method.....")
    }

    def test(age:Int): Unit = {
        println("test method.....")
    }
}

运行结果:
Alt text

Java字节码规范没有函数概念,函数怎么实现的呢?

函数的本质:将Scala的字节码反编译可以看出,如下图,函数就是Java字节码中的方法。增加了修饰符private static final, 其中final导致函数不能被重写重载,static使得函数可以直接调用,而不需要通过对象调用,可以发现字节码中函数名称发生变化,这是因为避免和Scala方法发生冲突。另外main方法中调用test$1();也说明就近原则优先调用的是函数。 Alt text

3. 函数定义

有以下这些情况:

  1. 函数 1:无参,无返回值
  2. 函数 2:无参,有返回值
  3. 函数 3:有参,无返回值
  4. 函数 4:有参,有返回值
  5. 函数 5:多参,无返回值
  6. 函数 6:多参,有返回值
scala
def main(args: Array[String]): Unit = {
    // 函数1:无参,无返回值
    def test1(): Unit = {}

    // 函数2:无参,有返回值
    def test2(): String = {
        "scala"
    }
    // 没有参数的函数被调用时可以简写
    test1
    test2
    // 函数3:有参,无返回值
    def test3(args:String): Unit={
        println("test3")
    }
    // 需要注意Scala函数如果有参数不能简写成以下格式:
    // test3 "demo"   // 只有Scala方法支持这么写
    // 函数4:有参,有返回值
    def test4(args:String): String={
        println(args)
        "test4"
    }
    // 函数5:多参,无返回值
    def test5(name:String, age:Int): Unit={
        println("name: "+ name+ "age: "+age)
    }
    // 函数6:多参,有返回值
    def test6(name:String, age:Int):(String, Int)={
        (name, age)
    }
}

4. 函数参数

  1. 可变参数
  2. 如果参数列表中存在多个参数,那么可变参数一般放置在最后
  3. 参数默认值,一般将有默认值的参数放置在参数列表的后面
  4. 带名参数
scala
def main(args: Array[String]): Unit = {
    // 可变参数
    def test(s: String*): Unit = {
        println(s)
    }
    // 有输入参数:输出 Array
    test("Hello", "Scala")
    // 无输入参数:输出 List()
    test()

    // 多个参数可以类型加上*表示,如果参数列表中存在多个参数,那么可变参数一般放置在最后
    def test2(name: String, s: String*): Unit = {
        println(name + "," + s)
    }
    test2("jinlian", "dalang")

    // (3)参数默认值, 因为参数默认是val声明, 参数默认值需要在声明的时候赋值
    def test3(name: String, age: Int = 30): Unit = {
        println(s"$name, $age")
    }
    // 如果参数传递了值,那么会覆盖默认值
    test3("jinlian", 20)
    // 如果参数有默认值,在调用的时候,可以省略这个参数
    test3("dalang")
    // 一般情况下,将有默认值的参数放置在参数列表的后面
    def test4(sex: String = "男", name: String): Unit = {
        println(s"$name, $sex")
    }
    // 如果默认值参数放置在前面,由于参数传值顺序默认从左到右,如果传参按照自己的顺序,需要带名参数
    //(4)带名参数
    test4(name = "ximenqing")
}

5. 函数至简原则

所谓的至简原则,其实就是Scala的作者为了开发人员能够大幅度提高开发效率。通过编译器的动态判定功能,帮助我们将函数声明中能简化的地方全部都进行了简化。也就是说将函数声明中那些能省的地方全部都省掉。函数至简原则:能省则省💋

  1. return可以省略,Scala会使用函数体的最后一行代码作为返回值。
  2. 如果函数体只有一行代码,可以省略花括号。
  3. 返回值类型如果能够推断出来,那么可以省略和返回值类型一起省略。
  4. 如果有return,则不能省略返回值类型,必须指定。
  5. 如果函数明确声明Unit,那么即使函数体中使用return关键字也不起作用。
  6. Scala如果期望是无返回值类型,可以省略等号。
  7. 如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加。
  8. 如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略。
  9. 如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略。
scala
def main(args: Array[String]): Unit = {
    def test(): Unit = {
        println("test....")
    }

    // 如果函数有返回值,可以省略return
    def test1(): String = {
        "hehe"
    }

    // 如果函数的逻辑代码只有一行,可以将大括号省略
    def test2(): String = "hehe"

    // 如果能够通过返回值推断出返回值类型,返回值类型可以省略
    def test3() = "hehe"

    // 如果函数参数没有,可以省略括号
    // 因为省略了很多语法内容,所以函数声明和变量声明很像了,所以必须使用def关键字区分
    def test4 = "hehe"

    println(test4) // println(test4()) 调用不加括号的函数不能在调用的时候加上括号

    // 如果函数有返回值,但是函数声明为Unit,此时return不起作用
    def test5(): Unit = {
        return "hehe"
    }

    println(test5())
    // def和函数名都省略的时候,称之为匿名函数, 需要使用=>进行关联
    () => {
        "test"
    }
}

运行结果:
Alt text