第5章 scala函数式编程(重要)

本文深入探讨Scala的函数式编程,包括基础函数编程概念,如基本语法、函数与方法的差异,以及函数至简原则。同时,讲解了高阶函数编程,涵盖函数作为值、参数、返回值的使用,匿名函数、闭包、柯里化和递归函数的实践。通过实例解析,帮助读者理解函数式编程在解决实际问题中的应用。
摘要由CSDN通过智能技术生成

第5章 函数式编程(重要)

在之前Java课程的学习中,我们一直学习的就是面向对象编程,所以解决问题都是按照面向对象的方式来处理的。比如用户登陆等业务功能,但是接下来,我们会学习函数式编程,采用函数式编程的思路来解决问题。scala编程语言将函数式编程和面向对象编程完美地融合在一起了。

  • 面向对象编程

分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题

  • 函数式编程

将问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用这些封装好的功能按照指定的步骤,解决问题。

5.1 基础函数编程

5.1.1 基本语法

[修饰符] def 函数名 ( 参数列表 ) [:返回值类型] = {
    函数体
}

private def test( s : String ) : Unit = {
    println(s)
}

5.1.2 函数&方法

  • scala 中存在方法与函数两个不同的概念,二者在语义上的区别很小。scala 方法是类的一部分,而函数是一个对象,可以赋值给一个变量。换句话来说在类中定义的函数即是方法。scala 中的方法跟 Java 的类似,方法是组成类的一部分。scala 中的函数则是一个完整的对象。

  • l Scala中的方法和函数从语法概念上来讲,一般不好区分,所以简单的理解就是:方法也是函数。只不过类中声明的函数称之为方法,其他场合声明的就是函数了。类中的方法是有重载和重写的。而函数可就没有重载和重写的概念了,但是函数可以嵌套声明使用,方法就没有这个能力了,千万记得哟。

5.1.3 函数定义

  1. 无参,无返回值
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun1(): Unit = {
            println("函数体")
        }
        fun1()
    }
}
  1. 无参,有返回值
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun2(): String = {
            "zhangsan"
        }
        println( fun2() )
    }
}
  1. 有参,无返回值
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun3( name:String ): Unit = {
            println( name )
        }
        fun3("zhangsan")
    }
}
  1. 有参,有返回值
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun4(name:String): String = {
            "Hello " + name
        }
        println( fun4("zhangsan") )
    }
}
  1. 多参,无返回值
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun5(hello:String, name:String): Unit = {
            println( hello + " " + name )
        }
        fun5("Hello", "zhangsan")
    }
}
  1. 多参,有返回值
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun6(hello:String, name:String): String = {
            hello + " " + name
        }
        println( fun6("Hello", "zhangsan"))
    }
}

5.1.4 函数参数

  1. 可变参数
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun7(names:String*): Unit = {
            println(names)
        }
        fun7()
        fun7( "zhangsan" )
        fun7( "zhangsan", "lisi" )
    }
}

可变参数不能放置在参数列表的前面,一般放置在参数列表的最后

oobject ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun777( name:String, names:String* ): Unit = {
            println( name )
            println( names )
        }
    }
}
  1. 参数默认值
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun8( name:String, password:String = "000000" ): Unit = {
            println( name + "," + password )
        }
        fun8("zhangsan", "123123")
        fun8("zhangsan")
    }
}
  1. 带名参数
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun9( password:String = "000000", name:String ): Unit = {
            println( name + "," + password )
        }
        fun9("123123", "zhangsan" )
        fun9(name="zhangsan")
    }
}

注意:可变参数和参数默认值是不能联合声明

object Scala04_Function_Normal_3 {

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

//        def test( password:String = "000000", name:String* ): Unit = {
//
//        }
//        // 可变参数和参数默认值是不能联合声明
//       // test()
//        test("000000")
//        test("000000", "zhangsan")
//        test("000000", "zhangsan", "lisi")
    }
}

5.1.5 函数至简原则

所谓的至简原则,其实就是Scala的作者为了开发人员能够大幅度提高开发效率。

通过编译器的动态判定功能,帮助我们将函数声明中能简化的地方全部都进行了简化。

也就是说将函数声明中那些能省的地方全部都省掉。所以这里的至简原则,简单来说就是:能省则省。

  1. 省略return关键字
// 函数体会将满足条件的最后一行的代码的执行结果作为函数的返回值
object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun1(): String = {
            return "zhangsan"
        }
        def fun11(): String = {
            "zhangsan"
        }
    }
}
  1. 省略花括号

如果函数体的逻辑代码只有一行的,那么大括号可以省略

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun2(): String = "zhangsan"
    }
}
  1. 省略返回值类型

如果函数返回数据,那么可以推断出返回值类型的话,返回值类型可以省略

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun3() = "zhangsan"
    }
}
  1. 省略参数列表

如果函数的参数列表中没有声明任何的参数,那么参数列表可以省略

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun4 = "zhangsan"
        fun4// OK
        fun4()//(ERROR)
    }
}
  1. 省略等号

如果函数体中有明确的return语句,那么返回值类型不能省略

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun5(): String = {
            return "zhangsan"
        }
        println(fun5())
    }
}

如果函数体返回值类型明确为Unit, 那么函数体中即使有return关键字也不起作用

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun5(): Unit = {
            return "zhangsan"
        }
        println(fun5())
    }
}

如果函数体返回值类型声明为Unit, 但是又想省略,那么此时就必须连同等号一起省略

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun5() {
            return "zhangsan"
        }
        println(fun5())
    }
}
  1. 省略名称和关键字

    关键字def和函数名也可以省略,称之为匿名函数

        // 省略的同时,也需要将返回值类型同时省略,将等号增加一个箭头
        // 匿名函数不能独立使用
        val f = () => {
            "zhangsan123"
        }

5.2 高阶函数编程

所谓的高阶函数,其实就是将函数当成一个类型来使用,而不是当成特定的语法结构。

5.2.1 函数作为值

函数也是个对象

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun1(): String = {
            "zhangsan"
        }
        val a = fun1
        val b = fun1 _
        val c : ()=>Unit = fun1
        println(a)
        println(b)
    }
}
object Scala06_Function_Hell {

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

        // TODO 函数式编程 - 地狱版

        // TODO 1. 函数也是个对象
        // User user = new User()
        //val f = ()=>{"zhangsan"}
        def fun1(): Unit = {
            println("fun1...")
        }

        val f1 = fun1 _
        //println("************")
        //val f2 = fun1()
        // 如果将函数作为整体,而不是执行结果赋值给变量,那么需要采用特殊符号:下划线
        //println("************")
        //f1()

        // 万物皆对象,但是对象都有类型,就意味着函数对象也有类型
        // 函数独立使用时,参数声明没有个数限制的,但是如果将函数作为对象给别人使用,那么函数的参数声明的个数最多为22个
        val f2 : Function0[Unit] = fun1 _
        //val f22 : Function22[] = fun1 _
        // 函数类型还有另外一种写法 : (输入参数类型)=>输出类型
        val f3 : () => Unit = fun1 _



        def test1( name:String, age:Int ):String = {
            "123"
        }

        // 之所以使用下划线让函数作为对象使用,因为代码中没有明确变量的类型,所以需要通过取值类推断
        // 如果变量声明的类型为函数类型,那么可以不使用下划线让函数作为对象
        val ff : (String, Int) => String = test1
        val f22 = ff _
        val f23 = ff 
        
    }
}

5.2.2 函数作为参数

将函数作为参数来使用

开始

//        def test(  f : ()=>Unit ): Unit = {
//            f()
//        }
//
//        // 函数对象
//        def fun1(): Unit = {
//            println("xxxxxxx")
//        }
//
//        val ff = fun1 _
//
//        test( ff )
        def test( f : (Int, Int) => Int ): Unit = {
            val r = f(10, 20)
            println(r)
        }

        def fun2(x:Int, y:Int): Int = {
            x + y
        }
        def fun3(x:Int, y:Int): Int = {
            x - y
        }
        def fun4(x:Int, y:Int): Int = {
            x * y
        }

        def fun5(x:Int, y:Int): Int = {
            x + y
        }

        test(fun2)
        test(fun3)
        test(fun4)

上面代码费事哈

匿名函数主要应用于函数作为参数使用

        test(
            (x:Int, y:Int) => {
                x - y
            }
        )

匿名函数在使用时也可以存在至简原则

        // TODO 匿名函数主要应用于函数作为参数使用
        test(
            (x:Int, y:Int) => {
                x - y
            }
        )
        // TODO 匿名函数在使用时也可以存在至简原则
        // 1. 如果函数体的逻辑代码只有一行,大括号可以省略,代码写在一行中
        test(
            (x:Int, y:Int) => x - y
        )
        // 2. 如果参数的类型可以推断出来,那么参数类型可以省略的
        test(
            (x, y) => x - y
        )
        // 3. 如果参数只有一个的话,参数列表的小括号可以省略
        // 4. 如果参数在使用时,按照顺序只使用了一次,那么可以使用下划线代替参数,
        test(_ - _)

案例2(强化):

object Scala06_Function_Hell_2 {

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

        // TODO 函数式编程 - 地狱版
        def test( f : (String)=>Unit ): Unit = {
            f("zhangsan")
        }

        def fun( name:String ): Unit = {
            println(name)
        }

        test(fun)
        //
        test(
            ( name:String ) => {
                println(name)
            }
        )
        test(
            ( name:String ) => println(name)
        )
        test(
            ( name ) => println(name)
        )
        test(
            name => println(name)
        )
        test(println(_)) // 匿名函数的至简原则的最终版
        test(println)  // 由于println 参数只有一个 可以省略括号
        test(fun)
    }
}

案例3(强化):

object Scala06_Function_Hell_3 {

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

        // TODO 函数式编程 - 地狱版
        def test( f : (Int, Int)=>Int ) = {
            f(10, 20)
        }

        test(
            (x:Int, y:Int) => {
                x + y
            }
        )

        test(
            (x:Int, y:Int) => x + y
        )

        println(
            test(
                (x, y) => 2 * x + y
            )
        )
        println(test(2*_ + _))
    }
}

强化4:

object Scala06_Function_Hell_4 {

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

        // TODO 函数式编程 - 地狱版
        def test( f : (String)=>Unit ): Unit = {
            f("zhangsan")
        }

        def fun(name:String): Unit = {
            println(name)
        }

        val f1 = fun _
        val f2 = fun _

        println(f1 eq f2)

        test(fun)

        test(
            (name:String) => {
                println(name)
            }
        )
        //1. 如果函数体的逻辑代码只有一行,大括号可以省略,代码写在一行中
        test(
            (name:String) => println(name)
        )
        //2. 如果参数的类型可以推断出来,那么参数类型可以省略的
        test(
            (name) => println(name)
        )
        //3. 如果参数只有一个的话,参数列表的小括号可以省略
        test(
            name => println(name)
        )
        //4. 如果参数在使用时,按照顺序只使用了一次,那么可以使用下划线代替参数,
        test(println(_))

    }
}

强化5:

object Scala06_Function_Hell_5 {

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

        // TODO 函数式编程 - 地狱版
        def test( x :Int, y:Int, f : (Int, Int)=>Int ): Unit = {
            val r = f(x, y)
            println(r)
        }

        test(10, 20, _+_)
        test(10, 20,
            (x:Int, y:Int) => {
                x + y
            }
        )

    }
}

5.2.3 函数作为返回值

将函数作为返回值返回

首先执行fun() ,他的返回结果是一个函数 test _ 给 这个函数加() 因此又能执行了
fun()()

object Scala06_Function_Hell_6 {

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

        // TODO 函数式编程 - 地狱版
        // TODO 3. 将函数作为返回值返回
        def test(): Unit = {
            println("function...")
        }

        def fun() = {
            test _
        }

        //val f = fun _
        //val ff = f()
        //ff()

        fun()()
        test()
    }
}
object Scala06_Function_Hell_7 {

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

        // TODO 函数式编程 - 地狱版
        // TODO 3. 将函数作为返回值返回, 一般应用于将内部的函数在外部使用
        // 这种方式不推荐自己定义类型
        def outer1() = {
            def inner1(): Unit = {
                println("inner...")
            }
            inner1 _
        }

        outer1()()

        def outer() = {
            def mid() = {
                def inner(): Unit = {
                    println("inner...")
                }
                inner _
            }
            mid _
        }
        outer()()()
    }
}

强化练习:

object Scala06_Function_Hell_8 {

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

        // TODO 函数式编程 - 地狱版
        // TODO 3. 将函数作为返回值返回, 一般应用于将内部的函数在外部使用

        // TODO 闭包
        // 一个函数使用了外部的变量,把这个变量包含到了它的内部来使用,改变了这个变量的生命周期
        // 将当前的代码形成了一个闭合的环境,这个环境称之为闭包环境,简称为闭包

        // Scala2.12版本前闭包功能采用的是匿名函数类型实现
        // Scala2.12版本闭包功能采用的是更改函数声明实现

        def outer( a : Int ) = {
            def inner( b : Int ): Int = {
                a + b
            }
            inner _
        }

        println(outer(10)(20))
        val f = outer(10)
        val ff = f(20)

        println(ff)

    }
}

5.2.4 匿名函数

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun4( f:Int => Int ): Int = {
            f(10)
        }
        println(fun4((x:Int)=>{x * 20}))
        println(fun4((x)=>{x * 20}))
        println(fun4((x)=>x * 20))
        println(fun4(x=>x * 20))
        println(fun4(_ * 20))
    }
}

5.2.7 控制抽象

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun7(op: => Unit) = {
            op
        }
        fun7{
            println("xx")
        }
    }
}
object Scala07_Function {

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

        // TODO 函数式编程 - 地狱版


        // TODO : 控制抽象
        // 抽象
        // 函数类型:() =>Unit
        //(op: ()=> Boolean)
        def myWhile(op: => Boolean)= {
            op
        }

        // 参数类型不完整,那么在传递参数时,也是不完整:只有传递代码就可以,不需要完整的声明
        // 可以采用控制抽象设计语法
        Breaks.breakable {
            for ( i <- 1 to 5 ) {
                Breaks.break()
            }
        }

//        val age = 10
//        myWhile( age < 20 ) {
//            println("xxx")
//        }
//
//
//        while( age < 20 ) {
//            println("xxx")
//        }

    }

5.2.5 闭包

object Scala06_Function_Hell_8 {

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

        // TODO 函数式编程 - 地狱版
        // TODO 3. 将函数作为返回值返回, 一般应用于将内部的函数在外部使用

        // TODO 闭包
        // 一个函数使用了外部的变量,把这个变量包含到了它的内部来使用,改变了这个变量的生命周期
        // 将当前的代码形成了一个闭合的环境,这个环境称之为闭包环境,简称为闭包

        // Scala2.12版本前闭包功能采用的是匿名函数类型实现
        // Scala2.12版本闭包功能采用的是更改函数声明实现

        def outer( a : Int ) = {
            def inner( b : Int ): Int = {
                a + b
            }
            inner _
        }

        println(outer(10)(20))
        val f = outer(10)
        val ff = f(20)

        println(ff)

    }
}

思考一个问题: 没有使用外部变量还能称之为闭包吗?

5.2.6 函数柯里化

object Scala08_Function {

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

        // TODO 函数式编程 - 柯里化(Curry)

        // 将无关的参数分离开
        def test( a:Int, b:Int ): Unit = {
            for ( i <- 1 to a ) { // 10min
                println(i)
            }
            for ( j <- 1 to b ) { // 20min
                println(j)
            }
        }

        def test1(a:Int)(b:Int): Unit = {
            for ( i <- 1 to a ) { // 10min
                println(i)
            }
            for ( j <- 1 to b ) { // 20min
                println(j)
            }
        }

        val a = 10 // 10min
        val b = 20 // 20min
        test(a, b) // 60min
        test1(a)(b)
    }
}

5.2.7 递归函数

object Scala09_Function {

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

        // TODO 函数式编程 - 递归
        //   1. scala中要求递归函数必须明确声明返回值类型
        //   2. 函数内部调用自身
        //   3. 一定要有跳出递归的逻辑
        //   4. 递归函数在调用时传递的参数之间有关系
        // 阶乘
        // 5!
        // StackOverflowError
        // Overflow : 滚动
//        def myRecursion(num:Int):Int = {
//            if ( num <= 1 ) {
//                1
//            } else {
//                num  myRecursion(num-1)
//            }
//        }
//
//        println(myRecursion(5))

        def myRecursion(num:Long):Long = {
            if ( num <= 1 ) {
                1
            } else {
                num + myRecursion(num-1)
            }
        }

        println(myRecursion(5000))

    }
}

思考两个问题:

  • 递归常用吗?
  • 递归会出问题吗?

5.2.9 惰性函数

当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数。

object ScalaFunction {
    def main(args: Array[String]): Unit = {
        def fun9(): String = {
            println("function...")
            "zhangsan"
        }
        lazy val a = fun9()
        println("----------")
        println(a)
    }
}

思考两个问题:

  • 函数到底是什么?实现原理?
  • 如果一台机器想让另外一台机器执行函数功能怎么办?

尚硅谷2022Java大数据线下面授班 完结

image-20220611100332425

链接: https://pan.baidu.com/s/1vcN1-S5st3azs_VRmxXMAg 提取码: s3vj
失效加V:x923713

QQ交流群 欢迎加入690763341

image-20220611100658881
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值