1) Object-oriented programming
Solve the problem, decompose the object, behavior, attribute, and then solve the problem through the relationship of the object and the call of the behavior.
Object: User
Behavior: login, connect to JDBC, read database
Attributes: username, password
Scala language is a completely object-oriented programming language. everything is an object
The essence of objects: an encapsulation of data and behavior
2) Functional programming
When solving a problem, decompose the problem into steps one by one, encapsulate each step (function), and solve the problem by calling these encapsulated steps.
For example: request->username, password->connect JDBC->read database
The Scala language is a fully functional programming language. Everything is a function.
The essence of functions: functions can be passed as a value
3) Functional programming and object-oriented programming are perfectly integrated in Scala.
5.1 Function basics
5.1.1 Function Basic Syntax
- basic grammar

2) Case Practice
Requirement: Define a function to print out the name passed in.
object TestFunction { def main(args: Array[String]): Unit = { // (1) Function definition def f(arg: String): Unit = { println(arg) } // (2) Function call // function name (parameter) f("hello world") } }
5.1.2 Difference between functions and methods
1) Core concepts
(1) A collection of program statements that accomplish a certain function is called a function.
(2) The functions in a class are called methods.
2) Case Practice
(1) Scala language can declare any syntax in any syntax structure
(2) Functions do not have the concept of overloading and rewriting; methods can be overloaded and rewritten
(3) Functions in Scala can be defined nestedly
object TestFunction { // (2) The method can be overloaded and rewritten, and the program can be executed def main(): Unit = { } def main(args: Array[String]): Unit = { // (1) Scala language can declare any syntax in any syntax structure import java.util.Date new Date() // (2) The function does not have the concept of overloading and rewriting, and the program reports an error def test(): Unit ={ println("No parameters, no return value") } test() def test(name:String):Unit={ println() } //(3) Functions in Scala can be defined nestedly def test2(): Unit ={ def test3(name:String):Unit={ println("Functions can be defined nested") } } } }
5.1.3 Function definition
1) Function definition
(1) Function 1: no parameters, no return value
(2) Function 2: no parameters, return value
(3) Function 3: There are parameters, but no return value
(4) Function 4: with parameters and return value
(5) Function 5: multiple parameters, no return value
(6) Function 6: Multiple parameters, return value
2) Case Practice
package com.learn.day05 /** * @author Lucaslee * @create 2023-02-02 15:56 */ object Test02_FunctionDefine { def main(args: Array[String]): Unit = { //no parameters and no return value def f1(): Unit = { println("no parameters and no return value") } // f1() println(f1()) println("=========================") // (2) Function 2: no parameters, return value def f2(): Int = { println("2. No parameters, return value") return 12 } println(f2()) println("=========================") // (3) Function 3: with parameters, no return value def f3(name: String): Unit = { println("3: With parameters, no return value " + name) } println(f3("alice")) println("=========================") // (4) Function 4: There are parameters and return values def f4(name: String): String = { println("4: There are parameters and return values " + name) return "hi, " + name } println(f4("alice")) println("=========================") // (5) Function 5: Multiple parameters, no return value def f5(name1: String, name2: String): Unit = { println("5: Multiple parameters, no return value") println(s"${name1}and ${name2}all my good friends") } f5("alice","bob") println("=========================") // (6) Function 6: Multiple parameters, return value def f6(a: Int, b: Int): Int = { println("6: Multi-parameter, with return value") return a + b } println(f6(12, 37)) } }
5.1.4 Function parameters
1) Case Practice
(1) variable parameters
(2) If there are multiple parameters in the parameter list, the variable parameters are generally placed at the end
(3) The default value of the parameter, generally the parameter with the default value is placed behind the parameter list
(4) Named parameters
package com.learn.day05 /** * @author Lucaslee * @create 2023-02-02 16:07 */ object Test03_FunctionParameter { def main(args: Array[String]): Unit = { // (1) variable parameters def f1(str: String*): Unit = { println(str) } f1("alice") f1("aaa", "bbb", "ccc") // (2) If there are multiple **parameters in the parameter list, the variable parameters are generally placed at the end** def f2(str1: String, str2: String*): Unit = { println("str1: " + str1 + " str2: " + str2) } f2("alice") f2("aaa", "bbb", "ccc") // (3) The default value of the parameter, generally the parameter with the default value is placed behind the parameter list def f3(name: String = "atguigu"): Unit = { println("My school is " + name) } f3("school") f3() // (4) Named parameters def f4(name: String = "atguigu", age: Int): Unit = { println(s"${age}Year-old ${name}Study in Silicon Valley") } f4("alice", 20) //You can pass parameters out of order, as long as you specify the parameter name f4(age = 23, name = "bob") f4(age = 21) } }
5.1.5 The principle of simplicity of functions (emphasis)
The principle of simplicity of function: save what you can
1) The details of the principle of simplicity
(1) return can be omitted, and Scala will use the last line of code in the function body as the return value
(2) If the function body has only one line of code, the curly braces can be omitted
(3) If the return value type can be inferred, it can be omitted (: and the return value type are omitted together)
(4) If there is a return, the return value type cannot be omitted and must be specified
(5) If the function explicitly declares unit, then even if the return keyword is used in the function body, it will not work
(6) Scala can omit the equal sign if it is expected to be a non-return type
(7) If the function has no parameters, but the parameter list is declared, then when calling, parentheses can be added or not
(8) If the function has no parameter list, the parentheses can be omitted, and the parentheses must be omitted when calling
(9) If you don’t care about the name and only care about logic processing, then the function name (def) can be omitted
2) Case Practice
package com.learn.day05 /** * @author Lucaslee * @create 2023-02-02 16:19 */ //The principle of function to simplicity object Test04_Simplify { def main(args: Array[String]): Unit = { // (0) Function standard writing def f0(name: String): String = { return name } println(f0("atguigu")) println("==========================") // (1) return can be omitted, and Scala will use the last line of code in the function body as the return value def f1(name: String): String = { name } println(f1("atguigu")) println("==========================") // (2) If the function body has only one line of code, the curly braces can be omitted def f2(name: String): String = name println(f2("atguigu")) println("==========================") // (3) If the return value type can be inferred, it can be omitted (: and the return value type are omitted together) def f3(name: String) = name println(f3("atguigu")) println("==========================") // (4) If there is a return, the return value type cannot be omitted and must be specified // def f4(name: String) = { // return name // } // // println(f4("atguigu")) println("==========================") // (5) If the function explicitly declares unit, then even if the return keyword is used in the function body, it will not work def f5(name: String): Unit = { return name } println(f5("atguigu")) // (6) Scala can omit the equal sign if it is expected to be a non-return type def f6(name: String) { println(name) } println(f6("atguigu")) println("==========================") // (7) If the function has no parameters, but the parameter list is declared, then when calling, parentheses can be added or not def f7(): Unit = { println("atguigu") } f7() f7 println("==========================") // (8) If the function has no parameter list, the parentheses can be omitted, and the parentheses must be omitted when calling def f8: Unit = { println("atguigu") } // f8() f8 println("==========================") // (9) If you don’t care about the name and only care about logic processing, then the function name (def) can be omitted //normally def f9(name: String): Unit = { println(name) } //After omitting def, it becomes like this // Anonymous functions, lambda expressions (name: String) => { println(name) } println("==========================") } }
Simplification of lambda expressions:
object Test05_Lambda { def main(args: Array[String]): Unit = { val fun = (name: String) => { println(name) } fun("atguigu") println("========================") // Define a function that takes the function as a parameter input def f(func: String => Unit): Unit = { func("atguigu") } f(fun) f((name: String) => { println(name) }) println("========================") // Simplification Principles for Anonymous Functions // (1) The type of the parameter can be omitted, and it will be automatically deduced according to the formal parameter f((name) => { println(name) }) // (2) After the type is omitted, if it is found that there is only one parameter, the parentheses can be omitted; in other cases: parentheses can never be omitted if there are no parameters and parameters exceed 1. f( name => { println(name) }) // (3) If the anonymous function has only one line, the braces can also be omitted f( name => println(name) ) // (4) If the parameter appears only once, the parameter is omitted and the following parameter can be replaced by _ f( println(_) ) // (5) If it can be inferred that the currently passed println is a function body, not a call statement, you can directly omit the underscore f( println ) println("=========================") // Practical example, define a "binary operation" function, which only operates two numbers 1 and 2, but the specific operation is passed in through parameters def dualFunctionOneAndTwo(fun: (Int, Int)=>Int): Int = { fun(1, 2) } val add = (a: Int, b: Int) => a + b val minus = (a: Int, b: Int) => a - b println(dualFunctionOneAndTwo(add)) println(dualFunctionOneAndTwo(minus)) // Anonymous function simplification println(dualFunctionOneAndTwo((a: Int, b: Int) => a + b)) println(dualFunctionOneAndTwo((a: Int, b: Int) => a - b)) println(dualFunctionOneAndTwo((a, b) => a + b)) println(dualFunctionOneAndTwo( _ + _)) println(dualFunctionOneAndTwo( _ - _)) println(dualFunctionOneAndTwo((a, b) => b - a)) println(dualFunctionOneAndTwo( -_ + _)) } }
5.2 Advanced functions
5.2.1 Higher-order functions
In Scala, functions are first-class citizens. How did it manifest?
For a function we can **: define function, call function**
object TestFunction { def main(args: Array[String]): Unit = { // Call functions foo() } // define function def foo():Unit = { println("foo...") } }
But in fact, there are higher-order usages of functions
1) Functions can be passed as values
object TestFunction { def main(args: Array[String]): Unit = { //(1) Call the foo function and give the return value to the variable f //val f = foo() val f = foo println(f) **//(2) Adding _ after the called function foo is equivalent to treating the function foo as a whole and passing it to the variable f1** val f1 = foo _ foo() f1() **//(3) If the variable type is clear, the function can be passed to the variable as a whole without using an underscore** var f2:()=>Int = foo } def foo():Int = { println("foo...") 1 } }
2) Functions can be passed as parameters
object Test05_Lambda { def main(args: Array[String]): Unit = { ** // (1) Define a function, the function parameter is still a function signature; f represents the function name; (Int,Int) represents the input of two Int parameter; Int Represents the return value of the function** def f1(f: (Int, Int) => Int): Int = { f(2, 4) } // (2) Define a function whose parameters and return value types are consistent with the input parameters of f1 def add(a: Int, b: Int): Int = a + b **// (3) Pass the add function as a parameter to the f1 function, if it can be deduced that it is not a call, _ can be omitted** println(f1(add)) println(f1(add _)) **//Anonymous functions can be passed** } }
3) Functions can be returned as function return values
object Test05_Lambda { def main(args: Array[String]): Unit = { def f1() = { def f2() = { } f2 _ } val f = f1() // Because the return value of the f1 function is still a function, the variable f can continue to be called as a function f() // The code above can be simplified to f1()() } }
5.2.2 Anonymous functions
1) Description
A function without a name is an anonymous function.
(x:Int)=>{function body}
x: Indicates the input parameter type;
Int: Indicates the input parameter type;
Function body: represents specific code logic
2) Case Practice
Requirement 1: The passed function has a parameter
Passing anonymous functions to simple principles:
(1) The type of the parameter can be omitted, and it will be automatically deduced according to the formal parameter
(2) After the type is omitted, if it is found that there is only one parameter, the parentheses can be omitted; in other cases: the parentheses can never be omitted if there are no parameters and the number of parameters exceeds 1.
(3) If the anonymous function has only one line, the braces can also be omitted
(4) If the parameter appears only once, the parameter is omitted and the following parameter can be replaced by _
package com.learn.day05 /** * @author Lucaslee * @create 2023-02-02 16:45 */ object Test05_Lambda { def main(args: Array[String]): Unit = { // (1) Define a function: parameters include data and logic functions def operation(arr: Array[Int], op: Int => Int) = { for (elem <- arr) yield op(elem) } // (2) Define the logic function def op(ele: Int): Int = { ele + 1 } // (3) Standard function call val arr = operation(Array(1, 2, 3, 4), op) println(arr.mkString(",")) // (4) Using anonymous functions val arr1 = operation(Array(1, 2, 3, 4), (ele: Int) => {ele + 1}) println(arr1.mkString(",")) // (4.1) The type of the parameter can be omitted, and it will be automatically deduced according to the formal parameter; val arr2 = operation(Array(1, 2, 3, 4), (ele) => {ele + 1}) println(arr2.mkString(",")) // (4.2) After the type is omitted, if it is found that there is only one parameter, the parentheses can be omitted; in other cases: if there are no parameters and the number of parameters exceeds 1, the parentheses can never be omitted. val arr3 = operation(Array(1, 2, 3, 4), ele => {ele + 1}) println(arr3.mkString(",")) // (4.3) If the anonymous function has only one line, the braces can also be omitted val arr4 = operation(Array(1, 2, 3, 4), ele => ele + 1) println(arr4.mkString(",")) //(4.4) If the parameter appears only once, the parameter is omitted and the subsequent parameter can be replaced by _ val arr5 = operation(Array(1, 2, 3, 4), _ + 1) println(arr5.mkString(",")) } }
Requirement 2: The passed function has two parameters
object TestFunction { def main(args: Array[String]): Unit = { def calculator(a: Int, b: Int, op: (Int, Int) => Int): Int = { op(a, b) } // (1) Standard Edition println(calculator(2, 3, (x: Int, y: Int) => {x + y})) // (2) If there is only one line, the braces can also be omitted println(calculator(2, 3, (x: Int, y: Int) => x + y)) // (3) The type of the parameter can be omitted, and it will be automatically deduced according to the formal parameter; println(calculator(2, 3, (x , y) => x + y)) // (4) If the parameter appears only once, the parameter is omitted and the following parameter can be replaced by _ println(calculator(2, 3, _ + _)) } }
extended exercise
Exercise 1: Define an anonymous function and assign it as a value to the variable fun. The function has three parameters, the types are Int, String, and Char, and the return value type is Boolean.
It is required to call the function fun(0, “”, ‘0’) to return false, and return true in other cases.
// 1. Exercise 1 //common writing def f(num: Int,str: String,cha: Char): Boolean ={ if(num == 0 && str == "" && cha == '0'){false} else {true} } //Anonymous function writing val fun = (num: Int,str: String,cha: Char) => { if(num == 0 && str == "" && cha == '0')false else true } println(fun(0, "", '0')) println(fun(0, "", '1')) println(fun(23, "", '0')) println(fun(0, "hello", '0')) output: false true true true
Exercise 2: Define a function func that takes an argument of type Int and returns a function (let it be f1).
It returns a function f1 that takes a parameter of type String and returns a function (denoted as f2) as well. The function f2 receives a parameter of type Char and returns a value of Boolean.
It is required to call the function func(0) ("") ('0') to get the return value false, and return true in other cases.
// 2. Exercise 2 def func(i: Int): String=>(Char=>Boolean) = { def f1(s: String): Char=>Boolean = { def f2(c: Char): Boolean = { if (i == 0 && s == "" && c == '0') false else true } f2 } f1 } println(func(0)("")('0')) println(func(0)("")('1')) println(func(23)("")('0')) println(func(0)("hello")('0')) // Anonymous function shorthand def func1(i: Int): String=>(Char=>Boolean) = { s => c => if (i == 0 && s == "" && c == '0') false else true } println(func1(0)("")('0')) println(func1(0)("")('1')) println(func1(23)("")('0')) println(func1(0)("hello")('0')) // Currying def func2(i: Int)(s: String)(c: Char): Boolean = { if (i == 0 && s == "" && c == '0') false else true } println(func2(0)("")('0')) println(func2(0)("")('1')) println(func2(23)("")('0')) println(func2(0)("hello")('0'))
5.2.3 Higher-order function case
Requirements: simulate Map mapping, Filter filtering, Reduce aggregation
object TestFunction { def main(args: Array[String]): Unit = { // (1) map mapping def map(arr: Array[Int], op: Int => Int) = { for (elem <- arr) yield op(elem) } val arr = map(Array(1, 2, 3, 4), (x: Int) => { x * x }) println(arr.mkString(",")) // (2) filter filter. If there are parameters, and the parameters are only used once, then the parameters are omitted and the following parameters are represented by _ def filter(arr:Array[Int],op:Int =>Boolean) ={ var arr1:ArrayBuffer[Int] = ArrayBuffer[Int]() for(elem <- arr if op(elem)){ arr1.append(elem) } arr1.toArray } var arr1 = filter(Array(1, 2, 3, 4), _ % 2 == 1) println(arr1.mkString(",")) // (3) reduce aggregation. There are multiple parameters, and each parameter is used only once, then the parameter The number is omitted and the following parameters are used_said that the first n indivual_On behalf of n parameters def reduce(arr: Array[Int], op: (Int, Int) => Int) = { var init: Int = arr(0) for (elem <- 1 until arr.length) { init = op(init, elem) } init } //val arr2 = reduce(Array(1, 2, 3, 4), (x, y) => x * y) val arr2 = reduce(Array(1, 2, 3, 4), _ * _) println(arr2) } }
5.2.4 Function currying & closure
Closures: a standard feature of functional programming
1) Description
Closure: If a function accesses the value of its external (local) variables, then this function and its environment are called closures
Function Currying: Turn multiple parameters of a parameter list into multiple parameter lists.
2) Case Practice
(1) closure
object TestFunction { def main(args: Array[String]): Unit = { def f1()={ var a:Int = 10 def f2(b:Int)={ a + b } f2 _ } // When calling, after the execution of the f1 function is completed, the local variable a should be released along with the stack space val f = f1() // But here, the variable a is actually not released, but contained inside the f2 function, forming a closed effect println(f(3)) println(f1()(3)) // Function currying, in fact, is to simplify the complex parameter logic, function currying must have a closure def f3()(b:Int)={ a + b } println(f3()(3)) } }
5.2.5 Recursion
1) Description
A function/method calls itself in the body of the function/method, we call it a recursive call
2) Case Practice
object TestFunction { def main(args: Array[String]): Unit = { // factorial // recursive algorithm // 1) The method calls itself // 2) The method must have the logic of jumping out // 3) When the method calls itself, the passed parameters should be regular // 4) Recursion in scala must declare the return value type of the function println(test(5)) } def test(i: Int): Int = { if (i == 1) { 1 } else { i * test(I - 1) } } }
import scala.annotation.tailrec object Test10_Recursion { def main(args: Array[String]): Unit = { println(fact(5)) println(tailFact(5)) } // Recursive implementation of calculating factorial def fact(n: Int): Int = { if (n == 0) return 1 fact(n - 1) * n } // Tail recursive implementation def tailFact(n: Int): Int = { @tailrec def loop(n: Int, currRes: Int): Int = { if (n == 0) return currRes loop(n - 1, currRes * n) } loop(n, 1) } }
5.2.6 Control abstraction
1) Value call: pass the calculated value to the past
object TestControl { def main(args: Array[String]): Unit = { def f = ()=>{ println("f...") 10 } foo(f()) } def foo(a: Int):Unit = { println(a) println(a) } }
2) Name call: pass the code over
object TestControl { def main(args: Array[String]): Unit = { def f = ()=>{ println("f...") 10 } foo(f()) } //def foo(a: Int):Unit = { def foo(a: =>Int):Unit = {//Note that the variable a has no parentheses here println(a) println(a) } } Output result: f... 10 f... 10
Note: Java only has call by value; Scala has both call by value and call by name.
3) Case Practice 1
object TestFunction { def main(args: Array[String]): Unit = { // (1) Pass code block foo({ println("aaa") }) // (2) Parentheses can be omitted foo{ println("aaa") } } def foo(a: =>Unit):Unit = { println(a) println(a) } }
4) Case Practice 2
object Test12_MyWhile { def main(args: Array[String]): Unit = { var n = 10 // 1. Regular while loop while (n >= 1){ println(n) n -= 1 } // 2. Implement a function with a closure, pass in the code block as a parameter, and call it recursively def myWhile(condition: =>Boolean): (=>Unit)=>Unit = { // The inner function needs to be called recursively, and the parameter is the loop body def doLoop(op: =>Unit): Unit = { if (condition){ op myWhile(condition)(op) } } doLoop _ } println("=================") n = 10 myWhile(n >= 1){ println(n) n -= 1 } // 3. Implementation with anonymous function def myWhile2(condition: =>Boolean): (=>Unit)=>Unit = { // The inner function needs to be called recursively, and the parameter is the loop body op => { if (condition){ op myWhile2(condition)(op) } } } println("=================") n = 10 myWhile2(n >= 1){ println(n) n -= 1 } // 3. Implemented with currying def myWhile3(condition: =>Boolean)(op: =>Unit): Unit = { if (condition){ op //Parameters by name ** Note: Java only has call-by-value; Scala has both call-by-value and call-by-name. ** myWhile3(condition)(op) } } println("=================") n = 10 myWhile3(n >= 1){ println(n) n -= 1 } } }

5.2.7 Lazy loading
1) Description
When a function return value is declared lazy, the execution of the function will be postponed until we first evaluate it, and the function will not execute. We call this kind of function a lazy function.
2) Case Practice
def main(args: Array[String]): Unit = { lazy val res = sum(10, 30) println("----------------") println("res=" + res) } def sum(n1: Int, n2: Int): Int = { println("sum be executed. . .") return n1 + n2 } } Output result: ---------------- sum be executed. . . res=40
Note: lazy cannot modify variables of type var