1. 简介

Fugue 是 Atlassian 推出的 Java 库,提供了一系列支持函数式编程的工具集。

本文将重点介绍 Fugue 中最核心的 API,帮你快速掌握这个实用工具库。

2. 快速上手

要在项目中使用 Fugue,先添加 Maven 依赖:

<dependency>
    <groupId>io.atlassian.fugue</groupId>
    <artifactId>fugue</artifactId>
    <version>4.5.1</version>
</dependency>

最新版本可在 Maven Central 查找。

3. Option 容器

先从 Option 类开始,这是 Fugue 对 java.util.Optional 的实现。

顾名思义,**Option 是一个可能为空的值容器**。

简单来说,Option 要么是 Some(包含值),要么是 None(空值):

Option<Object> none = Option.none();
assertFalse(none.isDefined());

Option<String> some = Option.some("value");
assertTrue(some.isDefined());
assertEquals("value", some.get());

Option<Integer> maybe = Option.option(someInputValue);

3.1. map 操作

函数式编程的标配方法 map(),用于对元素应用转换函数:

Option<String> some = Option.some("value") 
  .map(String::toUpperCase);
assertEquals("VALUE", some.get());

3.2. Option 与 null 值

除了命名差异,Fugue 在 Option 的设计上与 Optional 有几个关键区别:

**不能直接创建包含 null 的非空 Option**:

Option.some(null); // ❌ 直接抛异常

**但通过 map() 操作可以得到含 nullOption**:

Option<Object> some = Option.some("value")
  .map(x -> null);
assertNull(some.get()); // ✅ 允许

这点和 java.util.Optional 不同,后者会直接过滤掉 null

3.3. Option 是 Iterable

Option 实现了 Iterable 接口,可视为最多包含一个元素的集合。这极大提升了与集合/流的互操作性:

Option<String> some = Option.some("value");
Iterable<String> strings = Iterables
  .concat(some, Arrays.asList("a", "b", "c"));

3.4. 转换为 Stream

既然 OptionIterable,自然能轻松转为 Stream

assertEquals(0, Option.none().toStream().count()); // 空Option
assertEquals(1, Option.some("value").toStream().count()); // 非空Option

3.5. 与 Optional 互操作

需要标准 Optional 时?用 toOptional() 方法:

Optional<Object> optional = Option.none()
  .toOptional();
assertTrue(Option.fromOptional(optional)
  .isEmpty());

3.6. Options 工具类

Fugue 提供了 Options 工具类处理 Option 集合,核心方法包括:

  • filterNone:过滤掉空 Option
  • flatten:将 Option 集合展平为值集合
  • lift:将普通函数提升为处理 Option 的函数
Function<Integer, Integer> f = (Integer x) -> x > 0 ? x + 1 : null;
Function<Option<Integer>, Option<Integer>> lifted = Options.lift(f);

assertEquals(2, (long) lifted.apply(Option.some(1)).get());
assertTrue(lifted.apply(Option.none()).isEmpty());

⚠️ 注意:和 map 一样,lift 不会null 转为 None

assertEquals(null, lifted.apply(Option.some(0)).get()); // 返回null而非None

4. Either:处理双结果计算

Option 解决了值缺失问题,但有时需要返回更多信息(如错误对象)。这时 Either 就派上用场了。

Either 实例要么是 Right(成功结果),要么是 Left(错误结果),但不会同时存在

按惯例,Right 表示成功,Left 表示异常。

4.1. 创建 Either

通过静态工厂方法创建:

Either<Integer, String> right = Either.right("value"); // 成功结果
Either<Integer, String> left = Either.left(-1);        // 错误结果

这里计算可能返回 String(成功)或 Integer(错误码)。

4.2. 使用 Either

检查类型并处理:

if (either.isRight()) {
    // 处理成功结果
}

更函数式的链式调用:

either
  .map(String::toUpperCase)
  .getOrNull();

4.3. 投影(Projections)

EitherOption/Try 的主要区别在于它是无偏的(unbiased)。直接调用 map() 时,Either 不知道该处理 Left 还是 Right

投影(Projections)解决了这个问题:

左/右投影是 Either 的镜像视图,分别聚焦于左值或右值

either.left()
  .map(x -> decodeSQLErrorCode(x)); // 只对Left值生效

如果 EitherLeft,则应用 decodeSQLErrorCode();如果是 Right,则跳过。右投影同理。

4.4. 工具方法

类似 Options,Fugue 提供了 Eithers 工具类,包含过滤、类型转换、遍历 Either 集合等方法。

5. Try:异常处理

最后介绍 Fugue 的双结果类型变体——Try

Try 类似 Either,但专用于异常处理。像 Option 一样,它是单类型参数化(因为另一类型固定为 Exception)。

所以 Try 要么是 Success(成功),要么是 Failure(异常):

assertTrue(Try.failure(new Exception("Fail!")).isFailure());
assertTrue(Try.successful("OK").isSuccess());

5.1. 创建 Try

通常不会显式创建 Try,而是通过方法调用生成:

Checked.of 调用函数并封装结果或异常:

assertTrue(Checked.of(() -> "ok").isSuccess()); // 成功
assertTrue(Checked.of(() -> { throw new Exception("ko"); }).isFailure()); // 异常

Checked.lift 将抛异常的函数提升为返回 Try 的函数:

Checked.Function<String, Object, Exception> throwException = (String x) -> {
    throw new Exception(x);
};
        
assertTrue(Checked.lift(throwException).apply("ko").isFailure()); // 返回Failure

5.2. 操作 Try

拿到 Try 后,常见操作有三类:

  1. 提取值
  2. 链式操作成功值
  3. 用函数处理异常

其他方法基本都是这三类的变体。

5.3. 提取成功值

getOrElse 提取值:

assertEquals(42, failedTry.getOrElse(() -> 42)); // 失败时返回默认值

没有 getOrThrow,但可以简单实现:

someTry.getOrElse(() -> {
    throw new NoSuchElementException("Nothing to get");
});

5.4. 链式调用

函数式风格下,无需显式提取值即可操作:

Try<Integer> aTry = Try.successful(42).map(x -> x + 1); // 链式map

同样支持 flatMap

Try.successful(42).flatMap(x -> Try.successful(x + 1));

5.5. 异常恢复

有专门的方法处理异常(而非成功值),核心思想是**从异常中恢复,生成成功的 Try**。

recover 生成新值:

Try<Object> recover = Try
  .failure(new Exception("boo!"))
  .recover((Exception e) -> e.getMessage() + " recovered.");

assertTrue(recover.isSuccess());
assertEquals("boo! recovered.", recover.getOrElse(() -> null));

恢复函数接收异常作为参数。如果恢复函数本身抛异常,结果仍是失败的 Try

Try<Object> failure = Try.failure(new Exception("boo!")).recover(x -> {
    throw new RuntimeException(x); // 恢复函数抛异常
});

assertTrue(failure.isFailure()); // 结果仍是Failure

flatMap 的对应方法是 recoverWith

Try<Object> recover = Try
  .failure(new Exception("boo!"))
  .recoverWith((Exception e) -> Try.successful("recovered again!"));

assertTrue(recover.isSuccess());
assertEquals("recovered again!", recover.getOrElse(() -> null));

6. 其他工具

最后快速浏览 Fugue 的其他实用工具。

6.1. Pair 元组

Pair 是简单通用的数据结构,包含两个等重要的组件(称为 leftright):

Pair<Integer, String> pair = Pair.pair(1, "a");
        
assertEquals(1, (int) pair.left());
assertEquals("a", pair.right());

Fugue 对 Pair 提供的方法不多(主要是映射和应用函子模式),但它在库中广泛使用,用户代码也可直接使用。

6.2. Unit 单元

Unit 是单值枚举,表示“无值”。作为 void 返回类型和 Void 类的替代,避免 null

Unit doSomething() {
    System.out.println("Hello! Side effect");
    return Unit(); // 返回Unit而非void
}

但有个坑:**Option 不理解 Unit,会将其视为普通值而非空值**。

6.3. 静态工具类

Fugue 提供了多个静态工具类,避免重复造轮子:

  • Functions:函数组合、应用、柯里化、偏函数(基于 Option)、弱记忆化等
  • Suppliers:类似 Functions,但专用于无参函数(Supplier
  • Iterables/Iterators:操作 Java 标准集合接口的工具方法

7. 总结

本文介绍了 Atlassian Fugue 库的核心功能。未涉及代数结构类(如 MonoidSemigroups),因为它们不适合通用场景。

想深入了解?查阅 Javadoc源码。可选模块(如 Guava/Scala 集成)也值得探索。

所有示例代码可在 GitHub 项目 中找到(Maven 项目,可直接导入运行)。


原始标题:Introduction to Atlassian Fugue | Baeldung