由 JS 转 Java,写惯了 React,习惯了函数式,因此转 Java 时也是先学函数式。

语法糖「Syntactic Sugar」

起初,Java 的函数式看起来是匿名类的一个语法糖。

Stream.of(1, 2, 3).filter(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer % 2 == 0;
}
}).collect(Collectors.toList());
Stream.of(1, 2, 3).filter(x -> x % 2 == 0).collect(Collectors.toList());

后来,看到也能传方法引用时,我陷入了怀疑。

Stream.of(1, 2, 3).forEach(System.out::println);
StringBuilder sb = new StringBuilder();
Stream.of(1, 2, 3).forEach(sb::append);
System.out.println(sb.toString());
Stream.of(4, 2, 3).sorted(Integer::compareTo);

不过再想想,还是可以理解成语法糖:

Stream.of(1, 2, 3).forEach(System.out::println);

Stream.of(1, 2, 3).forEach(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});

闭包「Closure」

Java 闭包也是假的,和匿名类的限制一样,要求闭包访问的外部作用域变量是 final 的。实现应该都是:基础类型值传递,引用类型引用传递。

以下 Java 代码编译会报错:

int index = 0;
Stream.of("a", "b", "c")
.forEach(x -> System.out.println((index++) + ":" + x));

Error: Variable used in lambda expression should be final or effectively final

JS 闭包毫无问题:

let index = 0;
["a", "b", "c"].forEach(x => console.log(index++ + ":" + x));

尽管如此,但函数式习惯还是可以带到 Java 了。

第一个要带过来的是:少量的数据结构搭配大量的操作。

在 OOP 的世界里,开发者被鼓励针对具体的问题建立专门的数据结构,并以方法的形式,将专门的操作关联在数据结构上。函数式编程语言选择了另一种重用思路。它们用很少的一组关键数据结构( 如 list、 set、 map)来搭配专为这些数据结构深度优化过的操作。我们在这些关键数据结构和操作组成的一套运转机构上面,按需要“ 插入” 另外的数据结构和高阶函数来调整机器,以适应具体的问题。

Neal Ford. 函数式编程思维

在 Java 中,关键数据结构就是指 Stream

Stream 操作三板斧:mapfilterreduce

Java 和 JS 有些不一样。

不同点一:index 的取法

JS mapfilterreduce 都能拿到 index

["a", "b", "c"]
.map((s, index) => `${index}: ${s}`)
.forEach(s => console.log(s));

Java 想要 index 的信息,如果只是单线程,可以考虑利用引用类型保存迭代的索引:

AtomicInteger i = new AtomicInteger(0);
Stream.of("a", "b", "c")
.map(x -> i.getAndIncrement() + ":" + x)
.forEach(System.out::println);

如果想支持多线程,可以先通过 zip 让流中的数据带上 index

public static <T, R> List<Pair<T, R>> zip(List<T> s1, List<R> s2) {
return IntStream.range(0, Math.min(s1.size(), s2.size()))
.mapToObj(index -> new Pair<T, R>(s1.get(index), s2.get(index)))
.collect(Collectors.toList());
} public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c");
zip(IntStream.range(0, list.size()).boxed().collect(Collectors.toList()), list)
.parallelStream()
.map(p -> p.getKey() + ":" + p.getValue())
.forEach(System.out::println);
}

不同点二:reduce 的用法

Java 分为了 reductionmutable reduction,在 JS 里是不区分的。

A mutable reduction operation accumulates input elements into a mutable result container, such as a Collection or StringBuilder, as it processes the elements in the stream.

  • JS reduction:

    [1, 2, 3].reduce((acc, cur) => acc + cur, 0);
  • Java reduction:

    Stream.of(1, 2, 3).reduce(0, Integer::sum);
  • JS mutable reduction:

    [1, 2, 2].reduce((acc, cur) => {
    acc.add(cur);
    return acc;
    }, new Set());
  • Java mutable reduction:

    Stream.of(1, 2, 2).collect(
    () -> new HashSet<>(),
    (set, el) -> set.add(el),
    (s1, s2) -> s1.addAll(s2)
    );

    也可以简写为:

    Stream.of(1, 2, 2).collect(
    HashSet::new,
    HashSet::add,
    HashSet::addAll
    );

    参数比 JS 多了个 HashSet::addAll 是为了并行处理。


后续继续总结高阶函数、柯里化、函子在 Java 中的应用。

Java 函数式编程的更多相关文章

  1. paip.提升效率---filter map reduce 的java 函数式编程实现

    #paip.提升效率---filter map reduce 的java 函数式编程实现 ======================================================= ...

  2. 《深入理解Java函数式编程》系列文章

    Introduction 本系列文将帮助你理解Java函数式编程的用法.原理. 本文受启发于JavaOne 2016关于Lambda表达式的相关主题演讲Lambdas and Functional P ...

  3. Java函数式编程原理以及应用

    一. 函数式编程 Java8所有的新特性基本基于函数式编程的思想,函数式编程的带来,给Java注入了新鲜的活力. 下面来近距离观察一下函数式编程的几个特点: 函数可以作为变量.参数.返回值和数据类型. ...

  4. Java函数式编程:一、函数式接口,lambda表达式和方法引用

    Java函数式编程 什么是函数式编程 通过整合现有代码来产生新的功能,而不是从零开始编写所有内容,由此我们会得到更加可靠的代码,并获得更高的效率 我们可以这样理解:面向对象编程抽象数据,函数式编程抽象 ...

  5. Java函数式编程:二、高阶函数,闭包,函数组合以及柯里化

    承接上文:Java函数式编程:一.函数式接口,lambda表达式和方法引用 这次来聊聊函数式编程中其他的几个比较重要的概念和技术,从而使得我们能更深刻的掌握Java中的函数式编程. 本篇博客主要聊聊以 ...

  6. Java函数式编程:三、流与函数式编程

    本文是Java函数式编程的最后一篇,承接上文: Java函数式编程:一.函数式接口,lambda表达式和方法引用 Java函数式编程:二.高阶函数,闭包,函数组合以及柯里化 前面都是概念和铺垫,主要讲 ...

  7. Java函数式编程和lambda表达式

    为什么要使用函数式编程 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基于 ...

  8. 精练代码:一次Java函数式编程的重构之旅

    摘要:通过一次并发处理数据集的Java代码重构之旅,展示函数式编程如何使得代码更加精练. 难度:中级 基础知识 在开始之前,了解"高阶函数"和"泛型"这两个概念 ...

  9. [译]通往 Java 函数式编程的捷径

    原文地址:An easier path to functional programming in Java 原文作者:Venkat Subramaniam 译文出自:掘金翻译计划 以声明式的思想在你的 ...

  10. Java 函数式编程(Lambda表达式)与Stream API

    1 函数式编程 函数式编程(Functional Programming)是编程范式的一种.最常见的编程范式是命令式编程(Impera Programming),比如面向过程.面向对象编程都属于命令式 ...

随机推荐

  1. mysql-安装(windows版本)与登录

    安装mysql 1.MySQL版本 mysql-5.6.35-winx64.zip 2.首先解压到安装目录 3.修改配置文件 复制my-default.ini 重命名为my.ini 然后修改mysql ...

  2. React技巧之导入组件

    正文从这开始~ 总览 在React中,从其他文件中导入组件: 从A文件中导出组件.比如说,export function Button() {} . 在B文件中导入组件.比如说,import {But ...

  3. NC200190 矩阵消除游戏

    NC200190 矩阵消除游戏 题目 题目描述 牛妹在玩一个名为矩阵消除的游戏,矩阵的大小是 \({n}\) 行 \({m}\) 列,第 \({i}\) 行第 \({j}\) 列的单元格的权值为 \( ...

  4. 【UR #2】猪猪侠再战括号序列 题解

    题目链接 前言 是的没脑子选手只会做签到题. 思路分析 一开始把题目看成反转括号的状态,直接浪费 \(40\ mins\) . 我们考虑把不确定的"正确括号"转换成一个固定的括号序 ...

  5. Web开发小妙招:巧用ThreadLocal规避层层传值

    摘要:我们可以在处理每次请求的过程中,无需从Controller以及Service中的方法层层传值,只需要直接通过该局部变量取值即可. 本文分享自华为云社区<拦截器中巧用ThreadLocal规 ...

  6. JavaWeb的技术体系

    客户端和服务器端的交互 browser/ server(B/S)浏览器/服务器. client/server(C/S)应用/服务器.

  7. day05 Java网络编程socket 与多线程

    java网络编程 java.net.Socket Socket(套接字)封装了TCP协议的通讯细节,是的我们使用它可以与服务端建立网络链接,并通过 它获取两个流(一个输入一个输出),然后使用这两个流的 ...

  8. 零基础学Java(9)在mac上运行命令行提示"找不到或无法加载主类"

    天坑 遇到的问题:使用命令行执行命令:java EightSample,会报以下错误 错误: 找不到或无法加载主类 EightSample 运行环境 mac系统 IntelliJ IDEA编译器 Ja ...

  9. Mysql 系列 | 日志模块

    了解了 SQL 执行的流程,知道每一条语句都经过连接器.查询存储.分析器.优化器.执行器最后到存储引擎的过程.查询语句是如此,更新语句也不例外. 不同的是,更新语句会修改表数据,这里就涉及到两个重要的 ...

  10. JavaScript进阶内容——BOM详解

    JavaScript进阶内容--BOM详解 在上一篇文章中我们学习了DOM,接下来让我们先通过和DOM的对比来简单了解一下BOM 首先我们先来复习一下DOM: 文档对象模型 DOM把文档当作一个对象来 ...