位置:首页 > Scala > 大数据开发中Scala函数式编程实践与应用指南

大数据开发中Scala函数式编程实践与应用指南

时间:2026-08-21  |  作者:冻月看渠  |  阅读:0

一、什么是函数式编程

  • Scala是一门既面向对象,又面向过程的语言。
  • 在Scala中,函数与类、对象一样,都是一等公民。Ja va中,函数不能脱离类存在的。
  • Scala中的函数是一等公民,可以独立定义,独立存在,而且可以直接将函数作为值赋值给变量。
  • Scala的语法规定:将函数赋值给变量时,必须在函数后面加上空格和下划线。

1.1、匿名函数

  • Scala中的函数也可以不需要命名,这种函数称为匿名函数。
  • 匿名函数的语法格式:(参数名:参数类型)=>函数体。
  • 可以将匿名函数直接赋值给某个变量。
//匿名函数
val sayHelloFunc = (name: String) => println("Hello " + name)

1.2、高阶函数

  • 由于函数是一等公民,所以我们可以直接将某个函数作为参数传入其他函数。
  • 接收其他函数作为当前函数的参数,当前函数也被称为高阶函数。
  • 高阶函数可以自动推断出它里面函数的参数类型。
  • 对于只有一个参数的函数,还可以省去小括号。
package com.strivelearn.scala.scalafunction

/**
 * @author strivelearn
 * @version MyFunction.ja va, 2022年11月13日
 */
class MyFunction {
  //匿名函数
  val sayHelloFunc = (name: String) => println("Hello " + name)

  //高阶函数
  def sayHello(func: (String) => Unit, name: String): Unit = {
    func(name)
  }
}

object MyFunction {
  def main(args: Array[String]): Unit = {
    val function = new MyFunction()
    function.sayHello(function.sayHelloFunc, "World")
  }
}

1.3、常用的高阶函数

  • map

    大数据开发Scala函数式编程(第二十八篇)

    对传入的每个元素都进行处理,最终会返回一个元素。

  • flatMap

    对每个传入的元素都进行处理,然后返回一个或多个元素。

  • foreach

    对传入的每个元素都进行处理,没有返回值。

  • filter

    对传入的每个元素都进行一个条件判断,做过滤。

  • reduceLeft

    就好比hadoop的reduce一样,进行聚合操作,只不过这里是从左侧开始聚合。

二、词频统计

词频统计的核心思路:先拆分单词,再进行映射,最后聚合统计。

package com.strivelearn.scala.highorder

/**
 * @author strivelearn
 * @version WordCount.ja va, 2022年11月13日
 */
object WordCount {
  def main(args: Array[String]): Unit = {
    val str = "hello you hello me"
    val str1 = "hello hehe hello haha"
    val list = List(str, str1)
    //map简写
    list.flatMap(_.split(" ")).map(word => (word, 1))
    //map 这边定义一个元祖
    val i = list.flatMap(_.split(" ")).map((_, 1)).map(tup => tup._2).reduceLeft(_ + _)
    println(i)
  }
}

三、Scala的高级特性

3.1、模式匹配

  • Scala没有Ja va种的switch case语法,但是,Scala提供了更加强大的match case语法,即模式匹配。
  • Ja va的switch case仅能匹配变量的值,Scala的match case可以匹配各种情况。
  • 比如:变量的类型,集合的元素,有值没有值。
  • 语法格式:变量 match{case 值=>代码}
  • 在match case只要有一个分支满足条件,就不会走其他分支。
  • 这与Ja va不一样,Ja va需要使用break语法。
package com.strivelearn.scala.highorder

import ja va.io.{FileNotFoundException, IOException}

/**
 * @author strivelearn
 * @version Demo.ja va, 2022年11月13日
 */
object Demo {
  def test(day: Int): Unit = {
    day match {
      case 1 => println("星期一")
      case 2 => println("星期二")
      case 3 => println("星期三")
      case 4 => println("星期四")
      case 5 => println("星期五")
      case 6 => println("星期六")
      case 7 => println("星期日")
      case _ => println("none")
    }
  }

  def processException(e: Exception): Unit = {
    e match {
      case e1: FileNotFoundException => println("FileNotFoundException")
      case e2: IOException => println("IOException")
      case _: Exception => println
    }
  }

  def main(args: Array[String]): Unit = {
    test(1)
    processException(new IOException)
  }
}

3.2、case class

  • case class称为样例类,类似于Ja va中的Ja vaBeaen,只定义field。Scala自动提供getter和setter方法,没有method。
  • case class的主构造函数接收的参数通常不需要使用var或者val修饰,Scala会自动使用val修饰。
  • Scala自动为case class定义了伴生对象,也就是object,并且定义了apply()方法,该方法接收主构造函数中相同的参数并返回case class对象。
package com.strivelearn.scala.caseclass

/**
 * @author strivelearn
 * @version Person.ja va, 2022年11月13日
 */
class Person {

}

case class Student(name: String, cla: String) extends Person

case class Teacher(name: String, sub: String) extends Person
package com.strivelearn.scala.caseclass

/**
 * @author strivelearn
 * @version Test.ja va, 2022年11月13日
 */
object Test {
  def check(p: Person): Unit = {
    p match {
      case Teacher(name, sub) => println(name + " " + sub)
      case Student(name, cla) => println(name + " " + cla)
      case _ => println("none")
    }
  }

  def main(args: Array[String]): Unit = {
    check(new Student("zhangsan", "class1"))
  }
}

3.3、Option与模式匹配

  • Option有两种值,Some->表示有值,None->表示没值。
  • Option通常会用于模式匹配中,用于判断某个变量是有值还是没值,这比null更加简洁明了。
def main(args: Array[String]): Unit = {
  val stringToInt = Map("a" -> 1, "b" -> 2)
  //直接报错。ja va.util.NoSuchElementException: key not found: a1
  //val i = stringToInt("a1")
  val maybeInt = stringToInt.get("a1")
  //输出None
  println(maybeInt)
}
def getAge(key: String, map: Map[String, Int]): Unit = {
  val age = map.get(key)
  age match {
    case Some(age) => println("age: " + age)
    case None => println("none")
  }
}

3.4、隐式转换

  • Scala的隐式转换,允许手动指定将某种类型的对象转换为其它类型的对象。
  • Scala的隐式转换,最核心的就是定义隐式转换函数,即implicit conversion function
  • 隐式转换函数与普通函数唯一的语法区别是要以implicit开头而且最好要定义函数返回类型。

Scala默认会自动使用两种隐式转换

  • 源类型:或者目标类型的伴生对象里面的隐式转换函数。
  • 当前程序作用域内可以用唯一标识符表示的隐式转换函数。
  • 如果隐式转换函数不在上述两种情况下,那么就必须手动使用import语法引入某个包下的隐式转换函数。
  • 建议:仅仅在需要进行隐式转换的地方。

隐式转换案例:让狗会飞

package com.strivelearn.scala.test

import scala.language.implicitConversions

/**
 * @author strivelearn
 * @version Dog.ja va, 2022年11月13日
 */
class Dog(val name: String) {

  implicit def obj2Bird(obj: Object): Bird = {
    if (obj.getClass == classOf[Dog]) {
      val dog = obj.asInstanceOf[Dog]
      new Bird(dog.name)
    } else null
  }
}

object DogTest{
  def main(args: Array[String]): Unit = {
    val dog = new Dog("旺财")
    val bird = dog.obj2Bird(dog)
    bird.fly()
  }
}
package com.strivelearn.scala.test

/**
 * @author strivelearn
 * @version Bird.ja va, 2022年11月13日
 */
class Bird(val name: String) {
  def fly() {
    println(name + "can fly")
  }
}

运行结果:旺财can fly

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多