函数式 Scala的重要基础!一文掌握!

简介: 函数式 Scala的重要基础!一文掌握!

请与OOP知识配套使用 效果更佳!

函数式编程

定义

计算=>数学函数 纯函数编程

应用

函数式编程的特性包括:

  1. 纯函数(Pure Function):纯函数是指具有相同输入始终产生相同输出,并且没有任何副作用的函数。纯函数不会修改传入的参数或者对外部状态进行修改,它仅仅根据输入计算并返回结果,使得代码更加可靠、可测试和可维护。
  2. 不可变数据(Immutable Data):函数式编程鼓励使用不可变数据,即数据在创建后不可被修改。当需要修改数据时,函数式编程会创建新的数据副本,而不是修改原始数据。这种特性使得代码更易于推理和调试,并且可以避免由于数据共享导致的意外修改问题。
  3. 函数组合(Function Composition):函数式编程支持将多个函数组合在一起形成新的函数。通过将一个函数的输出作为另一个函数的输入,可以创建更复杂的函数逻辑。这种方式可以提高代码的可重用性和可读性,并且降低了副作用的影响。
  4. 高阶函数(Higher-Order Function):函数式编程支持高阶函数,即函数可以接受其他函数作为参数或返回函数作为结果。高阶函数可以灵活地组合和操作函数,使得代码更加灵活和模块化。
  5. 延迟求值(Lazy Evaluation):函数式编程中常用的延迟求值方式是通过惰性计算(Lazy Evaluation)来实现。惰性计算只在真正需要计算结果时才进行计算,可以避免不必要的计算开销,提高性能和效率。

函数式编程的特性使得代码更加模块化、易于理解和测试,并且能够处理并发和并行编程等复杂场景。它强调使用函数作为基本构建块,减少副作用和共享状态,以提高代码的可维护性和可扩展性。函数式编程在许多编程语言中都得到了广泛应用,并成为了现代软件开发中的重要编程范式之一。

具体使用方法

将定义好的匿名函数作为参数传给其他函数或者赋值给变量。

在需要函数的时候,直接定义函数的方法体,而不需要定义显性函数或者实现匿名内部类。

函数式接口

  1. Supplier<T>:无参数,返回一个结果。它对应的函数方法是 T get()。该接口常用于生成或提供数据,不接收任何输入参数,只产生一个结果。//供给

  2. Consumer<T>:接收一个参数,不返回任何结果。它对应的函数方法是 void accept(T t)。该接口常用于对传入的参数执行某种操作,例如打印、修改状态等。//消耗

  3. Function<T, R>:接收一个参数,返回一个结果。它对应的函数方法是 R apply(T t)。该接口常用于将一个类型的值转换为另一个类型的值,可以用于数据转换、映射等操作。//作用

  4. Predicate<T>:接收一个参数,返回一个布尔值。它对应的函数方法是 boolean test(T t)。该接口常用于对传入的参数进行条件判断,返回布尔值表示是否满足条件。//断言

    Consumer<String> consumer = (str) -> System.out.println(str);
    consumer.accept("Hello World!");
    
    Supplier<Integer> supplier = () -> 42;
    int result = supplier.get();
    System.out.println(result);
    
    Supplier<Integer> supplier = () -> 42;
    int result = supplier.get();
    System.out.println(result);
    
    Supplier<Integer> supplier = () -> 42;
    int result = supplier.get();
    System.out.println(result);
    
定义

函数式接口是指只包含一个抽象方法的接口。在Java中,函数式接口是用于支持函数式编程的重要概念。

设计目的
  1. 支持函数作为参数和返回值的传递,通过lambda表达式直接定义出一个匿名函数或者通过方法引用(lambda表达式)来引用其他地方的方法,并将这个方法直接去实现函数式接口中唯一的抽象方法。

  2. 无需关心具体的集合实现类(lambda表达式实现)

函数式

函数性质也是让函数式接口能够成为函数式编程中重要的一部分的一个原因。

1.默认方法和静态方法:不会破坏函数性质,同时又使功能更加丰富。

2.本身的设计目的就是为了支持函数作为返回值或者参数的传递

3.只包含一个抽象方法,表明这个接口实现了单一的函数行为,通过输入参数,进行计算,得出结果。

其他特点

注解标记:函数式接口可以使用@FunctionalInterface注解进行标记。该注解是可选的,但推荐使用。它提供了编译器级别的检查,确保接口仅包含一个抽象方法,以免引入错误。

Java标准库中的许多功能接口,如RunnableComparatorSupplier等,都是函数式接口的示例。此外,Java 8引入的java.util.function包提供了一组用于常见函数式接口的接口定义。

以下是一个简单的函数式接口示例:

javaCopy code@FunctionalInterface
interface MyFunction {
   
    void doSomething();
}

使用Lambda表达式可以实例化该函数式接口:

javaCopy codeMyFunction func = () -> {
   
    System.out.println("Doing something...");
};
func.doSomething();
应用
  1. 函数式编程:如果希望采用函数式编程的思维方式,使用纯函数和不可变数据,函数式接口是必不可少的。函数式接口提供了函数描述符,可以定义函数的输入和输出,并通过Lambda表达式或方法引用来实现具体的函数。
  2. 回调机制:当需要在特定事件发生时执行回调操作时,可以使用函数式接口来定义回调函数。通过函数式接口,可以将回调函数作为参数传递给需要监听事件的方法,并在事件发生时调用回调函数。
  3. 集合操作:函数式接口在集合操作中非常有用。例如,Java 8引入的Stream API就使用了函数式接口来进行集合的转换、过滤、映射等操作。通过使用函数式接口,可以以更简洁和声明式的方式对集合进行操作。
  4. 并行处理:函数式接口对于并行处理非常有用。Java 8引入的并行流和CompletableFuture等并发工具使用了函数式接口来描述并行执行的任务和操作。通过使用函数式接口,可以在多个线程上执行操作,并利用并行性来提高程序的性能。

Lambda表达式

定义

lambda表达式是用于定义一个无返回值,修饰符,其间包括参数列表,方法体匿名函数的函数式编程特性。

用途
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 使用Lambda表达式打印每个名称
names.forEach(name -> System.out.println(name));//多行语句要括号

// 使用方法引用简化Lambda表达式
names.forEach(System.out::println);

//如果Lambda表达式不需要参数,可以省略参数列表
() -> System.out.println("Hello")

MyFunction func = () -> {
   
    System.out.println("Doing something...");
};
func.doSomething();  // 调用抽象方法

//单个参数
最简单的Lambda表达式由参数列表、箭头符号(->)和表达式体组成
(int x)->x*x;
lambda特性分支之方法引用

方法引用 适用于 Function/Consumer接口。

list.stream().map(String::toUpperCase).forEach(e->System.out.println(e));

允许直接引用现有的方法或构造函数

格式:A(实例,类名 :: 构造方法,实例方法,静态方法)

方法引用的语法有以下几种形式:

  1. 静态方法引用:ClassName::staticMethodName 例如:Integer::parseInt表示引用了Integer类的parseInt静态方法。
  2. 实例方法引用:instance::instanceMethodName 例如:str::length表示引用了字符串strlength实例方法。
  3. 类的任意对象的实例方法引用:ClassName::instanceMethodName 例如:String::toUpperCase表示引用了String类的toUpperCase实例方法。
  4. 构造函数引用:ClassName::new 例如:ArrayList::new表示引用了ArrayList类的构造函数。

当使用方法引用时,我们可以将已存在的方法引用赋给函数式接口的实例,从而实例化该函数式接口。这是因为函数式接口只有一个抽象方法,我们可以通过方法引用将现有的方法与该抽象方法进行关联,从而创建函数式接口的实例。

例如,假设有一个函数式接口Converter,它包含一个抽象方法convert

javaCopy code@FunctionalInterface
interface Converter<T, R> {
   
    R convert(T input);
}

我们可以使用方法引用来实例化这个接口,将已存在的方法与convert方法进行关联。具体的方法引用取决于我们要引用的方法的签名和情况。

  1. 静态方法引用:

    javaCopy code
    Converter<String, Integer> converter = Integer::parseInt;
    
  2. 实例方法引用:

    javaCopy codeString str = "Hello, world!";
    Converter<String, Integer> converter = str::length;
    
  3. 类的任意对象的实例方法引用:

    javaCopy codeList<String> list = Arrays.asList("A", "B", "C");
    Converter<List<String>, Integer> converter = List::size;
    

通过方法引用,我们将已存在的方法与函数式接口的抽象方法进行绑定,实例化了该函数式接口。此时,我们可以通过调用该函数式接口的方法来执行与方法引用关联的方法。

此外,方法引用还可以在方法的传递和处理中使用。我们可以将一个接收函数式接口作为参数的方法,通过方法引用传递一个已存在的方法。这样,方法在被调用时就会执行与方法引用关联的方法。这种方式使得代码更加简洁和易读。

例如:

javaCopy codeList<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 使用方法引用将toUpperCase方法传递给map方法
List<String> upperCaseNames = names.stream()
                                   .map(String::toUpperCase)
                                   .collect(Collectors.toList());

在上述示例中,通过方法引用String::toUpperCase将字符串的toUpperCase方法传递给map方法,将每个字符串转换为大写形式。

这样,方法引用可以在函数式接口的实例化、方法的传递和处理中起到简化代码的作用,并提高代码的可读性和可维护性。

应用场景

排序(详见排序和比较.md),过滤,映射

过滤
List<Integer> numList = Arrays.asList(5,2,3,7,9);
        List<Integer> evenNumList = numList.stream().
                filter(e->e%2==0).
                collect(Collectors.toList());
映射
List<String> nameList = Arrays.asList("Henry","Lisa","Bob");
        List<String> upperCaseNameList = nameList.stream().
                map(String::toUpperCase).
                collect(Collectors.toList());
目录
相关文章
|
安全 算法 程序员
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
451 0
|
存储 安全 Java
ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别?
ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别?
|
存储 easyexcel Java
阿里easyexcel解析百万级大数据量的Excel表格,看这一篇文章就够了
阿里easyexcel解析百万级大数据量的Excel表格,看这一篇文章就够了
阿里easyexcel解析百万级大数据量的Excel表格,看这一篇文章就够了
|
C# 前端开发
WPF DatePicker默认显示当前日期,格式化为年月日
原文:WPF DatePicker默认显示当前日期 WPF的日历选择控件默认为当前日期,共有两种方法,一种静态,一种动态。 静态的当然写在DatePicker控件的属性里了,动态的写在对应的cs文件里,具体请看下面。
6905 0
|
11月前
|
API Kotlin
动态URL构建与HTTP请求的Kotlin实现
动态URL构建与HTTP请求的Kotlin实现
|
8月前
|
JSON API 数据安全/隐私保护
《揭秘:抖音电商 API 接口,让直播带货数据精准掌控!》
在数字营销时代,抖音电商API为直播带货提供数据支持。通过API可实时获取销售、用户互动等关键数据,助力商家优化策略,实现自动化分析与精准营销,提升效率并驱动业务增长。
858 0
|
分布式计算 监控 大数据
大数据-114 Flink DataStreamAPI 程序输入源 自定义输入源 Rich并行源 RichParallelSourceFunction
大数据-114 Flink DataStreamAPI 程序输入源 自定义输入源 Rich并行源 RichParallelSourceFunction
254 0
|
IDE 测试技术 开发工具
10个必备Python调试技巧:从pdb到单元测试的开发效率提升指南
在Python开发中,调试是提升效率的关键技能。本文总结了10个实用的调试方法,涵盖内置调试器pdb、breakpoint()函数、断言机制、logging模块、列表推导式优化、IPython调试、警告机制、IDE调试工具、inspect模块和单元测试框架的应用。通过这些技巧,开发者可以更高效地定位和解决问题,提高代码质量。
1200 8
10个必备Python调试技巧:从pdb到单元测试的开发效率提升指南
|
存储 缓存 Python
excel打开csv乱码解决------------为什么pycharm里面csv不乱码,excel里面却乱码了
excel打开csv乱码解决------------为什么pycharm里面csv不乱码,excel里面却乱码了
879 0
excel打开csv乱码解决------------为什么pycharm里面csv不乱码,excel里面却乱码了
|
应用服务中间件 Linux 网络安全
CentOS 7 上安装 Nginx
在 CentOS 7 上安装 Nginx 的步骤包括:添加 EPEL 仓库,安装 Nginx,启动 Nginx,配置防火墙规则,最后通过访问服务器 IP 验证安装是否成功
723 0