[scala-spark]4. 函数式编程

1. 几个概念说明

  • 在Scala中,方法与函数几乎可以等同(定义 使用 运行机制),只是函数的使用方法更加灵活多样
  • 函数式编程是从编程方式的角度来谈的。函数式编程把函数当成一等公民,充分利用函数、支持函数的多种使用方式(调用)。既可以作为函数的参数使用,也可以将函数赋值给一个变量;此外函数的创建不用依赖类或者对象,而在Java中,函数的创建需要依赖类/抽象类或者接口
package com.lineshen.chapter5

object method2FunctionDemo {
  def main(args: Array[String]): Unit = {
    val dog = new Dog
    val res1 = dog.sum(10, 20)
    println(res1)

    //方法转成函数
    val func = dog.sum _
    val res2 = func(20, 30)
    println(res2)

    //函数编程
    val func2 = (n1: Int, n2: Int) => n1 + n2
    val res3 = func2(30,40)
    println(res3)
  }
}

class Dog {
  def sum(n1: Int, n2: Int): Int = {
    n1 + n2
  }
}

>>30
>>50
>>70

函数的基本约定:

def 函数名([参数名:参数类型], ... ) [[:返回类型]] = {
  函数体
  return 返回值
}
  • 函数申明关键字是 def
  • [参数:参数类型] 表示函数的输入,可以没有,如果有多个,用逗号分割
  • 函数中的语句是为了实现某一功能的代码块
  • 函数可以有返回值,也可以没有;最好使用=,直接进行返回类型的推导
  • 如果没有 reture ,默认以执行到最后一行的结果作为返回值
package com.lineshen.chapter5

object FunDemo1 {
  def main(args: Array[String]): Unit = {
    val n1 = 1
    val n2 = 2

    println("sum="+getSum(n1,n2,"+"))
  }

  def getSum(n1: Int, n2: Int,opt: String) = {
    if (opt == "+"){
      n1 + n2
    } else if (opt == "-"){
      n1 - n2
    } else {
      null
    }
  }
}

本例中,n1+n2 / n1-n2 与 null的类型无法统一,就可以直接使用=进行返回类型的推导。

2. 函数递归

函数递归需要遵守的重要规则:

  • 程序执行函数时,就会创建一个新的受保护的独立空间(新函数栈)
  • 函数的局部变量是相互独立的,不会相互影响
  • 递归必须向逼近递归的条件逼近,否则就是无限递归

3. 函数的注意事项以及使用细节

  • 如果函数没有形参,那么函数调用过程中,不用写()
  • 形参列表和返回值列表的数据类型可以是值类型,也可以是引用类型
package com.lineshen.chapter5

object funcDetails {
  def main(args: Array[String]): Unit = {
    val tiger0 = new tiger
    println(tiger0.name)
    val tiger1 = test(100, tiger0)
    println(tiger1.name)
  }

  def test(n1:Int, tiger0:tiger): tiger= {
    println("n1="+ n1)
    tiger0.name = "jack"
    tiger0
  }
}

class tiger{
  var name = "lineshen"
}

输出结果: lineshen 100 jack

  • Scala中的函数可以根据函数体最后一行代码自动推断函数的返回值类型,该种情况下,return也可以不用写
  • 因为Scala可以自动推断返回值类型,因此,直接使用=就好了,或者用[:Any=]
  • 一旦使用return,就必须指定返回值类型 [:返回值类型];如果不指定,就是表示该函数没有任何返回值
  • 如果函数返回值制定了Unit,那么return无效
  • Scala支持高级嵌套,如类中可以再一次声明类;方法中可以继续定义方法
package com.lineshen.chapter5

object dupFunc {
  def main(args: Array[String]): Unit = {
    def sayOK(): Unit = { // private final sayOK$1
      println("say ok")

      def sayOK(): Unit = { // private final sayOK$2
        println("say ok, say ok")
      }
    }
  }
}
  • 形参可以进行初始化,默认调用;实参会覆盖形参;可以指定覆盖特定的形式参数默认值【带名参数】
  • Scala中的形参默认为是val,函数体中不允许去修改
  • 递归无法进行类型自动推导,必须指定返回类型
  • 支持可变形参,用for进行解析

4. 惰性函数

惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。惰性集合在需要时提供其元素,无需预先计算它们,这带来了一些好处。首先,可以将耗时的计算推迟到绝对需要的时候。其次,可以创造无限个集合,只要它们继续收到请求,就会继续提供元素。函数的惰性使用能够得到更高效的代码。Java并没有为惰性提供原生支持, Scala提供了,使用很方便。

object layDemo {
  def main(args: Array[String]): Unit = {
    lazy val res = sum(10, 20)
    println("-------------")
    println("-------------")
    println("-------------")

    println(res)
  }

  def sum(n1: Int, n2: Int): Int = {
    n1 + n2
  }

输出结果(lazy函数只能用val进行修饰,为了保证线程安全):

-------------
-------------
-------------
30

5. 异常处理

  • 抛出异常

Scala 抛出异常的方法和 Java一样,使用 throw 方法,例如,抛出一个新的参数异常:

throw new IllegalArgumentException
  • 捕捉异常

异常捕捉的机制与其他语言中一样,如果有异常发生,catch字句是按次序捕捉的。因此,在catch字句中,越具体的异常越要靠前,越普遍的异常越靠后。 如果抛出的异常不在catch字句中,该异常则无法处理,会被升级到调用者处。

捕捉异常的catch子句,语法与其他语言中不太一样(java使用了try-catch-catch-finnaly 无论有没有异常 finally代码块都会执行,一般用来释放资源)。在Scala里,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列case字句,如下例所示:

import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException

object exceptionDemo {
  def main(args: Array[String]) {
    try {
      val f = new FileReader("input.txt")
    } catch {
      case ex: FileNotFoundException => {
        println("Missing file exception")
      }
      case ex: IOException => {
        println("IO Exception")
      }
    }finally{
      println("Programming has run")
    }
  }
}

输出结果:

Missing file exception
Programming has run   【实际应用中,一般用于释放资源】

发布了652 篇原创文章 · 获赞 1573 · 访问量 298万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 代码科技 设计师: Amelia_0503

分享到微信朋友圈

×

扫一扫,手机浏览