Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 第5章:函数式编程的实践

第5章:函数式编程的实践

5.2 主流语言中的函数式特性

函数式编程(FP)不再局限于纯函数式语言(如 Haskell),许多主流语言通过内置特性或库支持 FP,以适应现代开发需求。本节将探讨 JavaScript 和 Java 中的函数式特性,分析它们的实现方式、应用场景以及如何在这些语言中实践 FP 的核心原则。通过对比,我们可以更全面地理解 FP 在不同语言中的体现。

JavaScript 的函数式编程

JavaScript 是一种动态语言,天然支持函数作为一等公民,这为 FP 提供了基础。自 ECMAScript 5 和 6 引入新特性后,其函数式能力显著增强。

  • 核心特性:

    • 函数作为一等公民:可以赋值、传递和返回函数。
    • 高阶函数:Array.map、Array.filter 和 Array.reduce。
    • 箭头函数:简洁的匿名函数语法。
    • 闭包:支持状态封装。
  • 示例:数据处理:

    const numbers = [1, 2, 3, 4];
    const squaredEvens = numbers
        .filter(x => x % 2 === 0)  // 筛选偶数
        .map(x => x * x);          // 平方
    console.log(squaredEvens);     // 输出: [4, 16]
    
  • 不可变性:
    JavaScript 的数组和对象默认可变,但可以用扩展运算符或库实现不可变更新:

    const obj = { a: 1, b: 2 };
    const newObj = { ...obj, a: 10 };  // 输出: { a: 10, b: 2 }
    console.log(obj);                  // 输出: { a: 1, b: 2 }
    
  • 库支持:

    • Ramda:提供柯里化、管道化和纯函数工具。
      const R = require('ramda');
      const double = x => x * 2;
      const triple = x => x * 3;
      const transform = R.pipe(double, triple);
      console.log(transform(5));  // 输出: 30
      
    • Lodash/FP:函数式版本的 Lodash。
  • 实践案例:事件处理:
    使用闭包和函数组合处理用户输入:

    const createLogger = prefix => msg => console.log(`${prefix}: ${msg}`);
    const errorLogger = createLogger('Error');
    errorLogger('Something went wrong');  // 输出: Error: Something went wrong
    
  • 局限:无尾递归优化,默认严格求值,需借助库(如 immutable.js)强化不可变性。

Java 的函数式编程

Java 是一种传统面向对象语言,但自 Java 8 引入 Lambda 表达式和 Stream API 后,显著融入了函数式特性。

  • 核心特性:

    • Lambda 表达式:简洁定义函数。
    • Stream API:支持 map、filter、reduce 等操作。
    • Optional:处理可能为空的值,类似 Maybe。
    • 函数式接口:如 Function、Predicate。
  • 示例:Stream 处理:

    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;
    
    public class Main {
        public static void main(String[] args) {
            List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
            List<Integer> squaredEvens = numbers.stream()
                .filter(n -> n % 2 == 0)      // 筛选偶数
                .map(n -> n * n)              // 平方
                .collect(Collectors.toList()); // 收集结果
            System.out.println(squaredEvens); // 输出: [4, 16]
        }
    }
    
  • 不可变性:
    Java 的集合默认可变,但 Stream 操作返回新集合,且 Collections.unmodifiableList 可冻结数据:

    import java.util.Collections;
    import java.util.ArrayList;
    
    List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
    List<Integer> immutable = Collections.unmodifiableList(list);
    // immutable.add(4);  // 抛出 UnsupportedOperationException
    
  • Optional 的使用:

    import java.util.Optional;
    
    Optional<String> maybeValue = Optional.of("Hello");
    String result = maybeValue.map(String::toUpperCase).orElse("None");
    System.out.println(result);  // 输出: HELLO
    
  • 库支持:

    • Vavr:提供不可变集合、模式匹配和更强的 FP 工具。
      import io.vavr.collection.List;
      
      List<Integer> numbers = List.of(1, 2, 3);
      List<Integer> doubled = numbers.map(x -> x * 2);
      System.out.println(doubled);  // 输出: List(2, 4, 6)
      
  • 实践案例:数据管道:

    List<String> words = Arrays.asList("apple", "banana", "cat");
    String lengths = words.stream()
        .filter(w -> w.length() > 3)
        .map(String::toUpperCase)
        .collect(Collectors.joining(", "));
    System.out.println(lengths);  // 输出: APPLE, BANANA
    
  • 局限:

    • Stream 需手动收集结果(如 .collect()),不够惰性。
    • 无原生尾递归优化。
    • 语法较冗长,FP 特性不如动态语言灵活。

对比与适用场景

  • JavaScript:

    • 适合:前端开发、事件驱动场景、快速原型。
    • 优势:动态性强,闭包易用。
    • 劣势:不可变性需额外努力。
  • Java:

    • 适合:企业级应用、大规模数据处理。
    • 优势:类型安全,Stream API 集成良好。
    • 劣势:语法较重,FP 非核心设计。

注意事项

  • 性能:高阶函数和不可变操作可能增加开销,需根据场景优化。
  • 习惯调整:从命令式转向函数式需适应新思维。
  • 工具选择:内置特性足够时无需过度依赖库。

小结

JavaScript 和 Java 通过各自的函数式特性,让开发者能在主流语言中实践 FP。JavaScript 的动态性和高阶函数适合快速开发,Java 的 Stream 和 Optional 则为静态类型系统增添了 FP 风味。理解这些特性,能让你在不同语言中灵活应用函数式思想。下一节,我们将介绍“函数式编程语言概览”,探索纯 FP 语言的魅力。

Last Updated:: 2/25/25, 10:59 AM