0701-Scala函数式编程

第一章 函数式编程

1.1 问题引入

有数组numberList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],编写程序完成以下目标:
- 1.1 将numberList中的每个元素加1得到一个新的数组
- 1.2 将numberList中的每个元素乘2得到一个新的数组
- 1.3 将numberList中的每个元素模3得到一个新的数组

1.2 实现

# 1.1 将numberList中的每个元素加1得到一个新的数组
def func1(numberList){
	newList = []
	for num in numberList:
    	newList.append(num + 1)
}
# 1.2 将numberList中的每个元素乘2得到一个新的数组
def func2(numberList){
	newList = []
	for num in numberList:
	    newList.append(num * 2)
}
# 1.3 将numberList中的每个元素模3得到一个新的数组
def func3(numberList){
	newList = []
	for num in numberList:
	    newList.append(num % 3)
}
# 调用函数
# 1.1 将numberList中的每个元素加1得到一个新的数组
func1(numberList)

# 1.2 将numberList中的每个元素乘2得到一个新的数组
func2(numberList)

# 1.3 将numberList中的每个元素模3得到一个新的数组
func3(numberList)

1.3 使用函数式编程进行改进

# 高阶函数`map`
# 该函数接受一个函数和一个数组作为输入,函数体中将这个函数作用于数组的每个元素然后作为返回值返回
def map(mappingFuction, numberList):
    newList = []
    for num in numberList:
        newList.append(mappingFuction(num))

# 调用函数
# 1.1 将numberList中的每个元素加1得到一个新的数组
map(lambda x: x + 1, numberList)

# 1.2 将numberList中的每个元素乘2得到一个新的数组
map(lambda x: x * 2, numberList)

# 1.3 将numberList中的每个元素模3得到一个新的数组
map(lambda x: x % 3, numberList)

1.4 什么是函数式编程

第二章 Scala函数式编程基础语法

2.1 函数声明

函数与方法:
java中的方法和Scala中的函数都可以进行功能的封装,但是方法必须和类型(类)绑定,但是函数不需要

def 函数名(参数名[:参数类型]…)[: 返回值类型 = ] {函数体}
  1. 无参, 无返回值
        // 无参 ,无返回值
        def test1(): Unit = {
            println("无参 ,无返回值")
        }
  1. 有参, 无返回值
        // 有参, 无返回值
        // Scala中没有重载的概念,如果在同一个作用域中,函数不能重名
        def test2(s: String): Unit = {
            println(s)
        }
  1. 有参, 有返回值
        // 有参,有返回值
        def test3(s: String): String = {
            return s + "--"
        }
  1. 无参, 有返回值
        // 无参,有返回值
        def test4(): String = {
            return "Hello World"
        }

2.2 自动推断, 能省则省

  1. 如果函数声明时,明确无返回值 Unit,那么即使函数体中有return也不起作用
        def test1(): Unit = {
            return "zhangsan"
        }
  1. 如果将函数体的最后一行代码进行返回,那么return关键字可以省略
        // 2.如果将函数体的最后一行代码进行返回,那么return关键字可以省略
        def test2(): String = {
            "zhangsan"
        }
  1. 如果可以根据函数体的最后一行代码推断出类型,那么函数的返回值类型可以省略
        // 3.如果可以根据函数体的最后一行代码推断出类型,那么函数的返回值类型可以省略
        def test3() = {
            "zhangsan"
        }
  1. 如果整个函数体只有一行代码,那么大括号可以省略
        def test4() = "zhangsan"
  1. 如果函数声明中没有参数列表,那么小括号可以省略
        def test5 = "zhangsan"

如果函数声明时省略小括号,那么调用函数时不能增加括号

  1. 如果明确函数没有返回值,那么 = 可以省略,最后一行代码也不会被返回
        def test6() {
            "zhangsan"
        }

如果函数没有参数列表,可以省略小括号,调用时一定不能加
如果函数没有参数列表,但是没有省略小括号,调用时 可加可不加

2.3 可变参数

        // TODO 可变参数
        def test1(name: String*) = {
            print(name)
        }

java中如何实现可变参数 String...

    public static void printMax( double... numbers) {
        if (numbers.length == 0) {
            System.out.println("No argument passed");
            return;
        }
 
        double result = numbers[0];
 
        for (int i = 1; i <  numbers.length; i++){
            if (numbers[i] >  result) {
                result = numbers[i];
            }
        }
        System.out.println("The max value is " + result);
    }

2.4 默认参数

        def test2(name: String, age: Int = 20): Unit = {
            print(name, age)
        }
        test2("zhangsan")

java中实现默认参数: 方法重载

    public static void main(String[] args) throws ParseException {
        // 日期格式化
        Date d = parse("2019-12-16 12:00:00", "yyyy-MM-dd HH:mm:ss");
    }
    public static Date parse(String date, String format) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
        return simpleDateFormat.parse(date);
    }

// 将format设为默认参数

    public static void main(String[] args) throws ParseException {
        // 日期格式化
        //Date d = parse("2019-12-16 12:00:00", "yyyy-MM-dd HH:mm:ss");

        // 将format设为默认参数
        Date parse = parse("2019-12-16 12:00:00");
    }
    public static Date parse(String date) throws ParseException {
        return parse(date, "yyyy-MM-dd HH:mm:ss");
    }
    private static Date parse(String date, String format) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
        return simpleDateFormat.parse(date);
    }

第三章 Scala高阶函数

3.1 函数作为参数

将函数作为参数传递给另外一个函数,需要采用特殊的声明方式
函数名:参数列表=>返回值类型 可以理解为 变量名 : 变量类型

  1. 定义函数, 指定函数作为参数
		// 高阶函数, 函数做参数, f是形参
        def f4(f: (Int) => Int) = {
            f(4) + 10
        }
        // 普通函数
        def f5(i: Int) = {
            i * 3
        }   
  1. 调用函数
        // 调用f4, 将f5作为参数传递给f4, f5 是实参
        val result: Int = f4(f5)
        println(result)

3.2 匿名函数

3.1 的写法太麻烦, 还需要再重新定义 f5, 使用匿名函数, 不必再定义f5

		// 定义高阶函数
        def f6(f: (Int) => Int): Int = {
            f(4) + 10
        }
        // 调用
        val result2: Int = f6(x => x * 3)
        println(result2)

3.3 函数作为返回值

        def f() = {
            println("function")
        }
        // TODO 函数作返回值
        def f0() = {
            // 返回函数本身,而不是返回函数的执行结果,但是,因为函数f是无参的,所以就算这里不加括号f()也是在调用f执行
            // f
            // 直接返回有问题,加特殊符号
            f _
        }
        f0()()

3.4 闭包

        // TODO 闭包
        // 一个函数在实现时,将外部变量引入到函数的内容,改 变了这个变量的生命周期,称之为闭包
        def f1(i: Int) = {
            def f2(j: Int) = {
                i * j
            }
            f2 _
        }
        f1(2)(3)

3.5 柯里化

        def f3(i: Int)(j: Int) = {
            i * j
        }
        f3(2)(3)

函数编程中,接受多个参数的函数都可以转化为接受单个参数的函数,这个转化过程就叫柯里化,柯里化就是证明了函数只需要一个参数而已。其实我们刚才的学习过程中,已经涉及到了柯里化操作,所以这也印证了,柯里化就是以函数为主体这种思想发展的必然产生的结果。

  1. 柯里化实例
		def mul(x: Int, y: Int) = x * y
		println(mul(10, 10))
		
		def mulCurry(x: Int) = (y: Int) => x * y
		println(mulCurry(10)(9))
		
		def mulCurry2(x: Int)(y:Int) = x * y
		println(mulCurry2(10)(8))

3.6 匿名函数的省略

        // TODO 省略的过程
        def f7(f: (Int, Int) => Int) = {
            f(10, 10)
        }
        // 原型
        f7((x: Int, y: Int) => {x + y})
        // 省略参数类型,自动推断
        f7((x, y) => {x + y})
        // 函数体只有一行代码,省略大括号
        f7((x, y) => x + y)
        // 参数只被使用了一次,用_代替
        f7(_ + _)
        f8((i: Int )=> {println(i)})
        f8((i)=> {println(i)})
        f8((i)=> println(i))
        f8((println(_)))
        f8(println

第四章 Java中的函数式编程

4.1 问题引入

    List<Employee> employees = Arrays.asList(
            new Employee("zhangsan",38,2999),
            new Employee("lisisddd",28,2399),
            new Employee("wangwuid",48,4599),
            new Employee("zhansdsd",58,6599),
            new Employee("zsdngsan",28,2399),
            new Employee("sddngsan",18,3199)
    );

    // 筛选年龄大于35岁的所有员工
    public List<Employee> filterByAge(List<Employee> employees) {
        List<Employee> emp = new ArrayList<>();
        for (Employee employee : employees) {
            if (employee.getAge() > 35) {
                emp.add(employee);
            }
        }
        return emp;
    }

    // 筛选年龄工资大于3000的所有员工
    public List<Employee> filterBySalary(List<Employee> employees) {
        List<Employee> emp = new ArrayList<>();
        for (Employee employee : employees) {
            if (employee.getSalary() > 3000) {
                emp.add(employee);
            }
        }
        return emp;
    }

    @Test
    public void test1() {
        // 按照年龄过滤
        List<Employee> employees = filterByAge(this.employees);
        for (Employee employee : employees) {
            System.out.println(employee);
        }

        // 按照工资过滤
        List<Employee> employees2 = filterBySalary(this.employees);
        for (Employee employee : employees2) {
            System.out.println(employee);
        }
    }

4.2 使用策略设计模式进行优化

4.2.1 定义策略接口

package com.lz.java8.lambda;

public interface MyFilter {
    public boolean test(Employee employee);
}

4.2.2 定义不同的策略

  1. 基于年龄过滤的策略
package com.lz.java8.lambda;

/**
 * @ClassName MyFilterByAge
 * @Description: TODO
 * @Author MAlone
 * @Date 2019/12/16
 * @Version V1.0
 **/
public class MyFilterByAge implements MyFilter {
    @Override
    public boolean test(Employee employee) {
        return employee.getAge() > 35;
    }
}
  1. 基于工资过滤的策略
package com.lz.java8.lambda;

/**
 * @ClassName MyFilterBySalary
 * @Description: TODO
 * @Author MAlone
 * @Date 2019/12/16
 * @Version V1.0
 **/
public class MyFilterBySalary implements MyFilter {
    @Override
    public boolean test(Employee employee) {
        return employee.getSalary() > 3000;
    }
}

4.2.3 设计基于策略的业务逻辑

    // 优化方式一: 策略设计模式
    public List<Employee> filterEmployee(List<Employee> employees, MyFilter filter) {
        List<Employee> emp = new ArrayList<>();
        for (Employee employee : employees) {
            if (filter.test(employee)) {
                emp.add(employee);
            }
        }
        return emp;
    }

4.2.4 根据具体的策略实现业务

    public void test2() {
        // 按照年龄过滤
        List<Employee> employees = filterEmployee(this.employees, new MyFilterByAge());
        // 按照工资过滤
        List<Employee> employees1 = filterEmployee(this.employees, new MyFilterBySalary());
    }

4.3 使用匿名内部类进行优化

解决策略设计模式,针对每种策略都要定义一个实现接口的策略类的问题

package com.lz.java8.lambda;

public interface MyFilter {
    public boolean test(Employee employee);
}

    public List<Employee> filterEmployee(List<Employee> employees, MyFilter filter) {
        List<Employee> emp = new ArrayList<>();
        for (Employee employee : employees) {
            if (filter.test(employee)) {
                emp.add(employee);
            }
        }
        return emp;
    }
    // 优化方式二: 匿名内部类
    public void test3() {
        // 按照年龄过滤
        List<Employee> employees = filterEmployee(this.employees, new MyFilter() {
            @Override
            public boolean test(Employee employee) {
                return employee.getAge() > 35;
            }
        });

        // 按照工资过滤
        List<Employee> employees1 = filterEmployee(this.employees, new MyFilter() {
            @Override
            public boolean test(Employee employee) {
                return employee.getSalary() > 3000;
            }
        });
    }

4.4 使用lambda表达式

package com.lz.java8.lambda;

public interface MyFilter {
    public boolean test(Employee employee);
}

    public List<Employee> filterEmployee(List<Employee> employees, MyFilter filter) {
        List<Employee> emp = new ArrayList<>();
        for (Employee employee : employees) {
            if (filter.test(employee)) {
                emp.add(employee);
            }
        }
        return emp;
    }
    // 优化方式三: lambda 表达式
    @Test
    public void test4() {
        // 按照年龄过滤
        filterEmployee(this.employees, (e) -> e.getAge() > 35);
        // 按照工资过滤
        filterEmployee(this.employees, (e) -> e.getSalary() > 3000);
    }

4.5 java8 内置的四大核心函数式接口

不用自己再去定义函数式接口,
即不用自己定义 MyFilter

4.5.1 Consumer : void accept(T t)

4.5.2 Supplier : T get()

4.5.3 Function< T, R > : R apply(T t)

4.5.4 Predicate : boolean test(T t)

4.6 优化方式四: 内置函数式接口

    // 优化方式四: 内置函数式接口
    public List<Employee> filterEmployee2(List<Employee> employees, Predicate<Employee> predicate) {
        ArrayList<Employee> emp = new ArrayList<>();
        for (Employee employee : employees) {
            if (predicate.test(employee)) {
                emp.add(employee);
            }
        }
        return emp;
    }

    public void test5() {
        // 按照年龄过滤
        filterEmployee2(this.employees, (e) -> e.getAge() > 35);
        // 按照工资过滤
        filterEmployee2(this.employees, (e) -> e.getSalary() > 3000);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值