VAVR:颠覆你的 Java 体验

VAVR,前身为Javaslang,是一个强大的Java库,旨在提升函数式编程体验。它提供了不可变集合、元组、Option、Try、Either、Future等工具,简化了代码并增强了错误处理。VAVR的模式匹配功能可以替代冗长的if..else,使其在Java世界中独树一帜。
摘要由CSDN通过智能技术生成

作者 | 田伟然

回首向来萧瑟处,归去,也无风雨也无晴。 

杏仁工程师,关注编码和诗词。

何方神圣?

众所周知, Java8 在一定程度上支持了函数式编程,但标准库提供的函数式 API 不是很完备和友好。

为了更好的进行函数式编程,我们就不得不借助于第三方库,而 VAVR 就是这方面的佼佼者,它可以有效减少代码量并提高代码质量。

VAVR 可不是默默无闻之辈,它的前身是发布于 2014 年的 Javaslang,目前在 github 上有着近 4k 的 star。

看到这儿,很多人就说我标题党了,一个 Java 库还来颠覆 Java ?

这可不不是我玩震惊体,打开 VAVR 的官网 ,它的首页就用加粗字体写着 「vavr - turns java™ upside down」

这翻译过来不就是颠覆 Java 吗?

食用指南

阅读本文需要读者对 Java8 的 lambda 语法和常用 API 有一定的了解。

由于是一篇框架的介绍文(地推 ing),为了避免写成官方文档的翻译,本文会有一些约束

  • 不会穷尽所有特性和 API,仅做抛砖引玉

  • 不会深入到源码细节

关于示例代码,基本会以单元测试的形式给出并保证运行通过

注:本文使用的 VAVR 版本为 0.10.3,JDK 版本为 11。

先来个概览

集合,全新的开始

不得不说 Java8 的集合库引入 Stream 以后确实很好用,但也正是因为使用了 Stream,不得不写很多样板代码,反而降低了不少体验。

// of 方法是 Java9 开始提供的静态工厂
java.util.List.of(1, 2, 3, 4, 5)
                .stream()
                .filter(i -> i > 3)
                .map(i -> i * 2)
                .collect(Collectors.toList());

而且 Java 的集合库本身是可变的,显然违背了函数式编程的基本特性 - 不可变,为此 VAVR 设计了一套全新的集合库,使用体验无限接近于 Scala。

更简洁的 API

io.vavr.collection.List.of(1, 2, 3, 4, 5)
    .filter(i -> i > 3)
    .map(i -> i * 2);

往集合追加数据会产生新的集合,从而保证不可变

var list = io.vavr.collection.List.of(1, 2)
var list2 = list
  .append(List.of(3, 4))
  .append(List.of(5, 6))
  .append(7);
// list = [1, 2]
// list2 = [1, 2, 3, 4, 5, 6]

强大的兼容性,可以非常方便的与 Java 标准集合库进行转换

var javaList = java.util.List.of(1, 2, 3);
java.util.List<Integer> javaList2 = io.vavr.collection.List.ofAll(javaList)
    .filter(i -> i > 1)
    .map(i -> i * 2)
    .toJavaList();

再来看一个稍微复杂一点的例子:过滤一批用户中已成年的数据,按照年龄对其分组,每个分组只展示用户的姓名。

/**
* 用户信息
*/
@Data
class User {
  private Long id;
  private String name;
  private Integer age;
}

先用 Java 标准集合库来实现这个需求,可以看见 collect(...) 这一长串嵌套是真的很难受

public Map<Integer, List<String>> userStatistic(List<User> users) {
    return users.stream()
      .filter(u -> u.getAge() >= 18)
      .collect(Collectors.groupingBy(User::getAge, Collectors.mapping(User::getName, Collectors.toList())));
}

再来看看 VAVR 的实现,是不是更简洁,更直观?

public Map<Integer, List<String>> userStatistic(List<User> users) {
    return users.filter(u -> u.getAge() >= 18)
      .groupBy(User::getAge)
      .mapValues(usersGroup -> usersGroup.map(User::getName));
}

VAVR 的集合库提供了更多 Functional 的 API,比如

  • take(Integer) 取前 n 个值

  • tail() 取除了头结点外的集合

  • zipWithIndex() 使得便利时可以拿到索引(不用 fori)

  • find(Predicate) 基于条件查询值,在 Java 标准库得使用 filter + findFirst 才能实现

  • .....

虽然代码实例都是用的 List,但是以上特性在 Queue、Set、Map 都可以使用,都支持与 Java 标准库的转换。

元组,Java 缺失的结构

熟悉 Haskell、Scala 的同学肯定对「元组」这个数据结构不陌生。

元组类似一个数组,可以存放不同类型的对象并维持其类型信息,这样在取值时就不用 cast 了。

// scala 的元组,用括号构建
val tup = (1, "ok", true)

// 按索引取值,执行对应类型的操作
val sum = tup._1 + 2  // int 加法
val world = "hello "+tup._2 // 字符串拼接
val res = !tup._3 // 布尔取反

当然,Java 并没有原生的语法支持创建元组,标准库也没有元组相关的类。

不过,VAVR 通过泛型实现了元组,通过 Tuple 的静态工厂,我们可以非常轻易的创建元组( 配合 Java10 的 var 语法简直不要太美好)

import io.vavr.Tuple;

public TupleTest {
  
    @Test
    public void testTuple() {
        // 一元组
        var oneTuple = Tuple.of("string");
        String oneTuple_1 = oneTuple._1;

        // 二元组
        var twoTuple = Tuple.of("string", 1);
        String twoTuple_1 = twoTuple._1;
        Integer twoTuple_2 = twoTuple._2;

      	// 五元组
        var threeTuple = Tuple.of("string", 2, 1.2F, 2.4D, 'c');
        String threeTuple_1 = threeTu
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值