Scala(五)函数式编程

函数式编程

  1面向对象编程

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

      对象用户;

      行为:登录、连接jdbc、读取数据库

      属性:用户名、密码

    Scala语言是一个完全面向对象编程语言。万物皆对象

  2)函数式编程

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

    例如请求->用户名、密码->连接jdbc->读取数据库

    Scala语言是一个完全函数式编程语言。万物皆函数

  3)在Scala中函数式编程和面向对象编程融合在一起了。

5.1 方法基本语法

  1)基本语法

  2案例实操

    需求:定义一个方法,实现将传入的名称打印出来。

package com.yuange.scala.day02

import scala.io.StdIn

object FunctionOne {
  def printName(name: String): Unit = println("name=" + name)

  def main(args: Array[String]): Unit = {
    println("请输入姓名:")
    printName(StdIn.readLine())
  }
}

5.2 方法声明

  1)方法声明

    (1)方法1:无参,无返回值

    (2)方法2:无参,有返回值

    (3)方法3:有参,无返回值

    (4)方法4:有参,有返回值

  2)案例实操

package com.yuange.scala.day02

object FunctionTwo {
  def main(args: Array[String]): Unit = {
    //无参,无返回值
    def test1() : Unit = {
      println("无参无返回值")
    }

    //无参,有返回值
    def test2() : String = {
      return "无参有返回值"
    }

    //有参,无返回值
    def test3(id: Int,name: String): Unit = {
      println("id=" + id + ",name=" + name)
    }

    //有参,有返回值
    def test4(id: Int,name:String): String = {
      return "id=" + id + ",name=" + name
    }
  }
}

5.3 方法参数

  1)案例实操

    (1)可变参数

    (2)如果参数列表中存在多个参数,那么可变参数一般放置在最后

    (3)参数默认值

    (4)带名参数

package com.yuange.scala.day02

object FunctionThree {
  def main(args: Array[String]): Unit = {
    test1("李白","杜甫","白居易")
    test1()
    //可变参数
    def test1(s: String*): Unit = {
      println(s)
    }

    test2(100)
    test2(1023,"赵云","刘备","曹操")
    //若参数列表存在多个参数,则可变参数一般放置在最后
    def test2(g: Int,s: String*): Unit = {
      println("g=" + g + ",s=" + s)
    }
    /*def test2(s: String*,g Int): Unit = { //error
      println("s=" + s + ",g=" + g)
    }*/

    test3(110)
    test3(120,"救护车")
    //参数默认值
    def test3(id: Int,name: String = "卢本伟"): Unit = {
      println("id=" + id + ",name=" + name)
    }

//    test4(1003) //error,Scala函数参数传递是从左到右,将有默认值的参数放在参数列表最后
    //带名参数
    test4(name="带名参数")
    def test4(id: Int = 1002,name: String): Unit = {
      println(s"id=${id},name=${name}")
    }
  }
}

5.4 方法至简原则

  方法至简原则:能省则省

  1至简原则细节

    1return可以省略,Scala会使用方法体的最后一行代码作为返回值

    (2)返回值类型如果能够推断出来,那么可以省略

    (3)如果方法体只有一行代码,可以省略花括号

    (4)如果方法无参,则可以省略小括号。若定义方法时省略小括号,则调用该方法时,也需省略小括号;若定义方法时未省略,则调用时,可省可不省。

    (5)如果方法明确声明Unit,那么即使方法体中使用return关键字也不起作用

    (6)Scala如果想要自动推断无返回值,可以省略等号

    (7)如果方法明确使用return关键字,那么方法返回就不能使用自行推断了,需要声明返回值类型

  2案例实操

package com.yuange.scala.day02

object FunctionFour {
  def main(args: Array[String]): Unit = {
    //标准写法
    def test1(name: String): String = {
      return name + "很牛逼"
    }
    println(test1("王五"))

    //return可以省略,scala会使用方法体的最后一行代码作为返回值
    def test2(name: String): String = {
      name + "牛逼Class"
    }
    println(test2("test2()孙斌"))

    //方法返回值若能推断出来,则可以省略返回值类型
    def test3(name: String) = {
      name + "十分嚣张"
    }
    println(test3("test3()张飞"))

    //若方法名使用return关键字,则方法不能使用自行推断,需声明返回值类型
    /*def test3(name: String) = { //error
      return name + "厉害"
    }*/

    //若方法体只有一行代码,则可以省略{}
    def test4(name: String) = name + "弱爆了"
    println(test4("test4()孙尚香"))

    //若方法无参,但声明了参数列表,则调用时()可加可不加
    def test5() = "test5()小括号可加可不加"
    println(test5())
    println(test5)

    //若方法无参且没有参数列表,则小括号可以省略,但调用方法时必须也省略
    def test6 = "test6()调用时必须也省略()"
//    println(test6())  //error
    println(test6)

    //若方法声明Unit,则即使方法体中使用return关键字也不会起作用
    def test7(name: String): Unit = {
      return "name=" + name
    }
    println(test7("test7()Judson"))   //打印()

    //若想自动推断无返回值,可以省略等号(等号和{}不能同时省略,将无返回值的方法称之为过程)
//    def test8(name: String) "name=" + name  //error
    def test8(name: String) {"name=" + name}
    println(test8("我是test8(),等号和{}不能同时省略"))   //打印()

    //若方法使用return关键字,则方法返回不能使用自动推断,需要声明返回值类型
    def test9(name: String): String = {  //error
        return "name=" + name
    }
    println("我是test9()")
//    def test9(name: String) = {  //error
//      return "name=" + name
//    }
  }
}

5.5 函数的基本语法

  1)基本语法:

    函数的返回值就是函数体中最后一个表达式的结果值

  2案例实操

    需求:定义一个函数,实现将传入的两个整数相加

package com.yuange.scala.day02

object FunctionFive {
  def main(args: Array[String]): Unit = {
    var plushFunction = (x: Int,y: Int) => {
      x + y
    }
    println(plushFunction(10,30))
  }
}

5.6 函数和方法的区别

  1)方法定义在类中可以实现重载,函数不可以重载

  2)方法是保存在方法区,函数是保存在堆中

  3)定义在方法中的方法可以称之为函数,不可以重载

  4)方法可以转成函数, 转换语法: 方法名 _

package com.yuange.scala.day02

object FunctionSix {
  //方法可以重载和重写,程序可以执行
  def main(): Unit = {

  }

  //方法
  def add(x: Int,y: Int) = x + y

  def main(args: Array[String]): Unit = {
    //可以在任何语法结构中声明任何语法
    import java.util.Date
    new Date()

    //函数没有重载和重写的概念
    var test = () => {
      println("无参无返回值")
    }
    test()
//    var test = (name: String) => {
//      println()
//    }

    //函数可以嵌套定义
    var test2 = () => {
      var test3 = () => {
        println("函数可以嵌套定义")
      }
    }

    //方法可以转成函数
    var add2 = add _
  }
}

5.7 高阶函数

  1定义:参数为函数的方法/函数称为高阶函数

  2案例实操

package com.yuange.scala.day02

object FunctionSeven {
  def main(args: Array[String]): Unit = {
    //高阶函数:以函数作为参数
    def calculator(a: Int,b: Int,operater: (Int,Int) => Int): Int = {
      operater(a,b)
    }

    //求和
    var add = (x: Int,y: Int) =>  x + y
    //求积
    var mul = (x: Int,y: Int) =>  x * y

    //调用
//    println(calculator(1,2,add))
//    println(calculator(1,2,mul))

//    println(calculator(1,2,(x,y) => x + y))  //简化
//    println(calculator(1,2,(x,y) =>  x * y))  //简化
    
    println(calculator(1,2,_ + _))  //再简化
    println(calculator(1,2,_ * _))  //再简化
  }
}

5.8 匿名函数

  1说明:没有名字的函数就是匿名函数,可以直接通过函数字面量(表达式)来设置匿名函数,函数字面量定义格式如下。

  2案例实操

package com.yuange.scala.day02

object FunctionEight {
  //高阶函数:函数可以作为参数
  def calculator(a: Int,b: Int,operater: (Int,Int) => Int): Int ={
    operater(a,b)
  }

  //求和
  var add = (x: Int,y: Int) => x + y
  //求积
  var mul = (x: Int,y: Int) => x * y

  def main(args: Array[String]): Unit = {
    //函数作为参数
    println(calculator(1,4,add))

    //匿名函数作为参数
    println(calculator(2,3,(x: Int,y: Int) => x * y))

    //匿名函数简写
    println(calculator(5,8,_ * _))
  }
}

5.9 函数柯里&闭包

  1说明:函数柯里化是指将一个接收多个参数的函数转化成一个接收一个参数的函数过程,可以简单的理解为一种特殊的参数列表声明方式。

    闭包:就是一个函数和与其相关的引用环境(变量)组合的一个整体(实体)

  2案例实操

    (1)闭包

package com.yuange.scala.day02

object FunctionNine {
  //外部变量
  var a1: Int = 10
  //闭包
  def test(a2: Int): Int = {
    a1 + a2
  }
}

    (2)柯里化

package com.yuange.scala.day02

object FunctionTen {
  //柯里化
  var sum = (x: Int,y: Int,z: Int) => x + y + z
  var sum1 = (x: Int) => {
    y: Int => {
      z: Int => {
        x + y + z
      }
    }
  }
  var sum2 = (x: Int) => (y: Int) => (z: Int) => x + y + z
  def sum3(x: Int)(y: Int)(z: Int) = x + y + z

  def main(args: Array[String]): Unit = {
    println(sum(1, 2, 3))
    println(sum1(1)(2)(3))
    println(sum2(1)(2)(3))
    println(sum3(1)(2)(3))
  }
}

5.10 递归

  1说明:一个函数/方法在函数/方法体内又调用了本身,我们称之为递归调用

  2案例实操

package com.yuange.scala.day02

object Recursion {
  def main(args: Array[String]): Unit = {
    /**
     * 递归算法
     * 1.方法调用自身
     * 2.方法最终能跳出循环逻辑
     * 3.方法调用自身时,传递的参数应该有规律
     * 4.scala中的递归必须声明函数返回值类型
     */
    println(test(10))
  }

  def test(a: Int): Int = {
    if (a == 1){
      1
    }else{
      a * test(a - 1)
    }
  }
}

5.11 控制抽象

  Scala中可以自己定义类似于if-elsewhile的流程控制语句,即所谓的控制抽象(说白了就是往函数/方法中传一个块表达式)

  案例:定义如下控制结构

loop(5){
  println("control")
}

  上述控制结构的功能为将println("control")循环执行5次。

  提示:scala中,以下结构称为代码块(block),可视为无参函数,作为 =>Unit类型的参数值。

{
    code
}

  实操:

package com.yuange.scala.day02

object ControlAbstraction {
  def loop(i: Int)(op: => Unit): Unit = {
    if (i > 0){
      op
      loop(i - 1)(op)
    }
  }

  def main(args: Array[String]): Unit = {
    loop(5){
      println("control")
    }
  }
}

5.12 惰性求值

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

  2案例实操

package com.yuange.scala.day02

object LazyEvaluation {
  var sum = (a1: Int,a2: Int) => {
    println("sum........")
    a1 + a2
  }

  def main(args: Array[String]): Unit = {
    lazy val result = sum(2,6)  //lazy不能修饰var类型的变量
    println("result="+result)
  }
}

5.13 高阶函数实战

  1)根据指定规则对集合中每个元素操作

    数据: Array("spark","hadoop","flume","kafka")

    规则: 获取每个元素的长度 [可变]

    结果: Array(5,6,5,5)

package com.yuange.scala.day02

object HighFunctionOne {
  def main(args: Array[String]): Unit = {
    /**
     * 根据指定规则对集合中每个元素操作
     * 数据: Array("spark","hadoop","flume","kafka")
     * 规则: 获取每个元素的长度 [可变]
     * 结果: Array(5,6,5,5)
     */
    var lists = Array("spark","hadoop","flume","kafka") //定义数据
    var func = (str: String) => str.length()  //定义函数:返回长度
//    println(getLength(lists,func).toList)
//    println(getLength(lists,str => str.length()).toList)  //简化
    println(getLength(lists,_.length()).toList)  //简化
  }

  /**
   * 获取长度
   * @param lists
   * @param func
   * @return
   */
  def getLength(lists: Array[String],func: String => Int) = {
    for(list <- lists) yield {
      func(list)
    }
  }
}

   2)根据指定规则对数据进行过滤

    数据: Array(10,2,4,5,7,9,20)

    规则: 过滤掉奇数数据 [可变]

    结果: Array(10,2,4,20)

package com.yuange.scala.day02

object HighFunctionTwo {
  def main(args: Array[String]): Unit = {
    /**
     * 根据指定规则对数据进行过滤
     * 数据: Array(10,2,4,5,7,9,20)
     * 规则: 过滤掉奇数数据 [可变]
     * 结果: Array(10,2,4,20)
     */
    var datas = Array(10,2,4,5,7,9,20)  //数据准备
    var function = (x: Int) => x%2==0   //函数准备
    //执行
    println(filterOdd(datas,function).toList)
  }

  def filterOdd(datas: Array[Int],function: Int => Boolean) ={
    for(data <- datas if (function(data))) yield{
      data
    }
  }
}

   3)根据指定规则获取集合中的最大元素

    数据: Array("zhangsan 20 3000","lisi 15 2500","zhaoliu 30 4000")

    规则: 获取年龄最大的人信息 [可变]

    结果: zhaoliu 30 4000

package com.yuange.scala.day02

object HighFunctionThree {
  def main(args: Array[String]): Unit = {
    /**
     * 根据指定规则获取集合中的最大元素
     * 数据: Array("zhangsan 20 3000","lisi 15 2500","zhaoliu 30 4000")
     * 规则: 获取年龄最大的人信息 [可变]
     * 结果: zhaoliu 30 4000
     */
    var datas = Array("zhangsan 20 3000","lisi 15 2500","zhaoliu 30 4000")
    var function = (data: String) => {
      var age = data.split(" ")(1).toInt
      age
    }
    println(getMax(datas,function))
  }

  def getMax(datas: Array[String],function: String => Int) = {
    var max= 0
    var maxDateInfo = ""
    for (data <- datas){
      var age = function(data)
      if (age > max){
        max = age
        maxDateInfo = data
      }
    }
    maxDateInfo
  }
}

   4)根据指定规则对集合中的元素进行分组

    数据: Array("zhangsan 男 shenzhen","lisi 女 beijing","zhaoliu 男 beijing")

    规则: 根据地址分组 [可变]

    结果: Map(shenzhen->List( "zhangsan 男 shenzhen" ), biejing->List( "lisi 女 beijing","zhaoliu 男 beijing") )

package com.yuange.scala.day02

import java.util

object HighFunctionFour {
  def main(args: Array[String]): Unit = {
    /**
     * 根据指定规则对集合中的元素进行分组
     * 数据: Array("zhangsan 男 shenzhen","lisi 女 beijing","zhaoliu 男 beijing")
     * 规则: 根据地址分组 [可变]
     * 结果: Map(shenzhen->List( "zhangsan 男 shenzhen" ), biejing->List( "lisi 女 beijing","zhaoliu 男 beijing") )
     */
    var datas = Array("zhangsan 男 shenzhen","lisi 女 beijing","zhaoliu 男 beijing")
//    var function = (str: String) => str.split(" ")(2)
//    println(addressGourp(datas,function))
//    println(addressGourp(datas,str => str.split(" ")(2))) //简化
    println(addressGourp(datas,_.split(" ")(2))) //简化
  }

  def addressGourp(datas: Array[String],function: String => String) = {
    var map = new util.HashMap[String,util.List[String]]()
    for (data <- datas){
      var address = function(data)
      //若map中存在该地址,则将data信息加入到到地址中的List集合中
      if (map.containsKey(address)){
        map.get(address).add(data)
      }else{
        var list = new util.ArrayList[String]
        list.add(data)
        map.put(address,list)
      }
    }
    map
  }
}

  5)根据指定规则对集合所有元素进行聚合

    数据: List(10,2,5,6,9,7)

    规则: 求和 [可变]

    结果: 39

package com.yuange.scala.day02

object HighFunctionFive {
  def main(args: Array[String]): Unit = {
    /**
     * 根据指定规则对集合所有元素进行聚合
     * 数据: List(10,2,5,6,9,7)
     * 规则: 求和 [可变]
     * 结果: 39
     */
    var datas = Array(10,2,5,6,9,7)
//    var function = (sum: Int,data: Int) => sum + data
//    println(polymerization(datas,function))
//    println(polymerization(datas,(sum,data) => sum + data))   //简化
    println(polymerization(datas,_ + _))   //简化
  }

  def polymerization(datas: Array[Int],function: (Int,Int) => Int) = {
    var sum = datas(0)
    for (i <- 1 until datas.length){
      sum = function(sum,datas(i))
    }
    sum
  }
}

原文地址:https://www.cnblogs.com/LzMingYueShanPao/p/14783814.html