每当JDK发布了新版本就有同学说“你发任你发,我用Java 8”,可在工作中有不少人依然不太擅长使用Java8的新特性,而这些特性往往让Java不再“臃肿”。不过我个人认为Java8所有的新特性中最具有代表性的一定是函数式编程。有人会说这种风格太抽象难懂了,当你熟练掌握这种设定之后,你一定会感到很香。慢慢地你也会领会到函数式编程的魅力和精髓。今天介绍一个函数式Java工具包,它表现了很多优秀的函数式编程思想。以前介绍的熔断降级组件Hystrix的替代品resilience4j就基于vavr库。

Vavr

Vavr是一个Java8函数库,它运用了大量的函数式编程范式。创造性地封装了一些持久性的数据结构和函数式控制结构。而且从中可以学到很多有用的编程思想。

可观察的副作用

我们的代码中经常会出现一些看不见的陷阱,从代码语义中这些陷阱是无法被观察的。例如

int divide(int a, int b){return a/b;
}

我们知道a/b会得到一个整数,但是却不能从代码上明确地知道如果b=0将会抛出java.lang.ArithmeticException异常;而如果是a+b则不会带来任何副作用。所以我们需要让这种副作用是可观察的。对于这一点Vavr做出了一种设计:

Try<Integer> divide(Integer a, Integer b) {return Try.of(() -> a / b);
}

将可能的副作用封装到一个容器中,明确了可能的失败,当你看到返回的是Try<Integer>时,就意味着结果可能“并不顺利”,以便于针对性地进行预防。

不可变的数据结构

很多语言都在使用不可变的数据结构,比如Golang、Kotlin。主要原因是不可变的值:

  • 本质上是线程安全的,因此不需要同步

  • 对于equalshashCode是可靠的

  • 不需要克隆

  • 在非受检unchecked类型转换中是类型安全的

  • 对于函数式编程来说不可变值是最透明的

为此Vavr设计了一个集合类库,旨在代替Java中的集合框架。Vavr 的集合库包含一组丰富的函数式数据结构,这些数据结构建立在 lambdas 之上。它们与 Java 原始集合共享的唯一接口是Iterable。这些数据结构是持久性的,一旦初始化本身就不可改变,你可以使用一些操作来返回更改后的副本。例如经典的数据结构单向链表:

// 1   2  3
List<Integer> source = List.of(1, 2, 3);

如果我们将一个新元素0放在原始链表尾部的前面

//  0  2  3
List<Integer> newHeadList = source.tail().prepend(0);
//  1  2  3
System.out.println(source);

原始链表保持不变,新的链表大小保持不变元素被替换了。当然你可以使用其它API来生成一个大小变化的副本,不过可以肯定的是原始的链表一定不会发生改变。

// 0 1 2 3
List<Integer> prepend = source.prepend(0);
// 1 2 3 0
List<Integer> append = source.append(0);

这只是其中的一部分编程思想,接下来我将介绍Vavr的一些特色。

Vavr的一些特色

Vavr提供了一些非常有用的而且有特色的API。

元组

熟悉Python的同学对元组(Tuple)一定不陌生。元组将固定数量的元素组合在一起,以便它们可以作为一个整体传递。与数组或列表不同,元组可以包含不同类型的对象,但它也是不可变的。目前Vavr提供了最多8个元素的元组结构。

// (felord.cn, 22)
Tuple2<String, Integer> java8 = Tuple.of("felord.cn", 22);
// felord.cn
String s = java8._1;
// 22
Integer i = java8._2;

这个可以用来模拟Java中不具有的多返回值的特性。

Function

Java本身提供了Function接口,但是Vavr则提供了更加丰富的Function扩展,例如可以组合多个Function

Function1<Integer, Integer> multiplyByTwo = a -> a * 2;
Function1<Integer, Integer> compose = multiplyByTwo.compose(a -> a + 1);
// 6
Integer apply = compose.apply(2);

除此之外,还可以让潜在的副作用降级(lift),有点类似于微服务的熔断,以避免在函数执行中处理异常

Function2<Integer, Integer, Integer> divide = (a, b) -> a / b;
// 降级
Function2<Integer, Integer, Option<Integer>> safeDivide = Function2.lift(divide);
// 返回一个加强版的Optional
Option<Integer> apply = safeDivide.apply(1, 0);
boolean empty = apply.isEmpty();
// true
System.out.println(empty);

还有派生操作:

 Function2<Integer, Integer, Integer> divide = (a, b) -> a / b;Function1<Integer, Integer> a = divide.apply(4);Integer apply = a.apply(2);

这有点类似于柯里化,当我们用到更多入参时柯里化才更加明显:

Function3<Integer, Integer, Integer, Integer> sum = (a, b, c) -> a + b + c;
final Function1<Integer, Function1<Integer, Integer>> add2 = sum.curried().apply(1);
Integer apply = add2.apply(2).apply(3);

猜一猜答案是几?

带有特性的值容器

这个不太好用中文说明,有一些值带有独特的性质,比如开头提到的Try,用来显式表明可能遇到异常。Vavr提供了很多具有独特性质的值容器。

Option

类似Optional,但是比Optional更加强大。

Lazy

Lazy是一个惰性计算的容器,表示当使用时才去计算且只计算一次。

Lazy<Double> lazy = Lazy.of(Math::random);
lazy.isEvaluated(); // = false
lazy.get();         // = 0.123
lazy.isEvaluated(); // = true
lazy.get();         // = 0.123
// 需要使用数据时才从数据源加载
Data lazyData = Lazy.val(DataSourceService::get, Data.class);

其它还有一些非常有用的容器,你可以尝试它们。

模式匹配

函数式编程语言大都支持模式匹配,同为JVM语言的Scala中就有这种特性,而Java目前是没有的。可以有效地帮助我们减少if-else,举个例子:

   public static String convert(int input) {String output;if (input == 1) {output = "one";} else if (input == 2) {output = "two";} else if (input == 3) {output = "three";} else {output = "unknown";}return output;}

你就说吧,绕不绕?,Vavr就清爽多了。

    public static String vavrMatch(int input) {return Match(input).of(Case($(1), "one"),Case($(2), "two"),Case($(3), "three"),Case($(), "unknown"));}

当然还有其它一些玩法需要你自己去发现。

总结

函数式编程作为Java8最大的一个亮点(个人认为),对于习惯于传统OOP编程的开发者来说确实不容易接受。你不妨从Vavr类库入手去学习函数式编程的思想。今天介绍的只是它很少的一部分,还有更多等着你去发现、去借鉴。忘记说了,如果你想在项目中引用它,可以引入下面这个坐标:

<!-- https://mvnrepository.com/artifact/io.vavr/vavr -->
<dependency><groupId>io.vavr</groupId><artifactId>vavr</artifactId><version>0.10.3</version>
</dependency>

往期推荐

Java17 新特性确定,Java之父:终于可以和一个长达25年的漏洞说再见了

是时候转型 Serverless 来玩微服务了吗?

还在用Jenkins?看看这些替代方案,是否更适合你!

Spring 面试题(2021最新版)赶紧收藏!

因一次骑行的脸刹着地,诞生了自动驾驶自行车!不愧是野生钢铁侠!太硬核了~~~

点下方卡片,关注作者:码农小胖哥

分享高质量编程知识,探讨IT人生

这个类库可以帮助你理解Java中的函数式编程相关推荐

  1. Java 中的函数式编程

    1. 概述 在本教程中,我们将了解函数式编程范式的核心原则以及如何在 Java 编程语言中使用它们. 我们还将介绍一些高级函数式编程技术.这将帮助我们了解 Java 中的函数式编程的好处. 2. 什么 ...

  2. c++返回指针时候注意提防_提防Java中的函数式编程!

    c++返回指针时候注意提防 这对函数式编程并不会造成太大的影响,这真棒. 这是关于某些实践的警告,您很可能会将其应用于您的代码,而这是完全错误的! . 高阶函数对于函数式编程是必不可少的,因此,谈论它 ...

  3. 提防Java中的函数式编程!

    这对函数式编程并不会造成太大的影响,这真棒. 这是关于某些实践的警告,您很可能会将其应用于您的代码,而这完全是错误的! . 高阶函数对于函数式编程是必不可少的,因此,谈论它们将帮助您成为聚会中的焦点. ...

  4. 在Java中应用函数式编程请小心!

    2019独角兽企业重金招聘Python工程师标准>>> 这并不是要对令人畏惧的函数式编程进行谴责,而是对编程中很容易发生的一些错误进行警醒. 高阶函数是函数式编程的关键,因此,谈论它 ...

  5. Java中的函数式编程(二)函数式接口Functional Interface

    写在前面 前面说过,判断一门语言是否支持函数式编程,一个重要的判断标准就是:它是否将函数看做是"第一等公民(first-class citizens)". 函数是"第一等 ...

  6. java猫抓老鼠_用猫抓老鼠的实例理解java中面向对象的编程与类和对象以及方法的概念...

    今天看到马士兵讲的关于面向对象编程的思路,用了一个猫抓老鼠的例子,我觉得这个例子非常形象,于是写在这里,方便学习理解和以后查看 class cat{ //声明一个类–"猫" int ...

  7. java函数式编程入口_Java中的函数式编程

    前言 JDK8引入的Lambda表达式和Stream为Java平台提供了函数式编程的支持,极大地提高了开发效率.本文结合网络资源和自身使用经验,介绍下Java中的函数式编程 Java中的函数式编程 出 ...

  8. 用通俗易懂的大白话搞明白Java里的函数式编程和Lambda表达式

    今天,用通俗易懂的大白话来彻底搞明白Java里的函数式编程和Lambda表达式 为什么引入函数式编程,lambda表达式? 大家都知道,JDK1.8引入了函数式编程,lambda表达式. 那有没有想过 ...

  9. 【Java】23 函数式编程

    函数式接口(Functional Interface)是 JDK 1.8 对一类特殊类型的接口的称呼. 这类接口有且仅有一个抽象方法,并且这类接口使用了 @FunctionalInterface 进行 ...

最新文章

  1. 剑指offer二之替换空格
  2. 二极管7种应用电路详解之六
  3. fibonacci数列前20项_等差数列、等比数列、调和数列等几种常见数列的总结
  4. 中国太阳能热水器市场营销模式探析与品牌格局调研报告2022版
  5. 理解Python的迭代器
  6. Unity与Android交互
  7. 【算法分析与设计】查找第K大/小元素问题
  8. jQuery Mobile中链接(包含button和表单提交的链接)的data-*选项
  9. 字符串统计--对于给定的一个字符串,统计其中数字字符出现的次数。
  10. 如何快速制作出精致的ppt模板?
  11. 教你玩转私域流量+会员运营体系
  12. 通天阁塔机器人图片_CORNER | 大阪 · 东京铁塔也比不过跟你一起看的通天阁
  13. 点赞封面未发送已删除_微信表白新功能:有种喜欢,是给你朋友圈封面点赞
  14. Eclipse中调试Python代码--调试FWTools2.4.7中的gdal_retile.py
  15. vue更换主题设置主题
  16. 03 学生免费注册Pycharm专业版
  17. Excel 2010 VBA 入门 095 数据处理之用数组实现分列
  18. 《大长今》分集剧情介绍(上)
  19. 阿里云无影研发负责人任晋奎:端云技术创新,打造全新用户体验
  20. Android快速银联集成支付

热门文章

  1. Sysinternals Suite 2012.06.28软件简介
  2. linux synproxy 抵御 ddos攻击的原理和优化
  3. 漫谈 Weblogic CVE-2020-2555
  4. linux tomcat 隐藏版本号
  5. 声明与函数、函数指针
  6. linux c 解析生成json(jansson安装和使用)
  7. http抓包工具推荐WSockExpert/httpwatch/HttpAnalyzer/DebugBar
  8. Linux命令 -- ps
  9. Linux 文件系统的目录结构
  10. Ubuntu Server16.04 中文安装报错无法安装busybox-initramf