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()
操作可以得到含 null
的 Option
**:
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
既然 Option
是 Iterable
,自然能轻松转为 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)
Either
和 Option
/Try
的主要区别在于它是无偏的(unbiased)。直接调用 map()
时,Either
不知道该处理 Left
还是 Right
。
投影(Projections)解决了这个问题:
左/右投影是 Either
的镜像视图,分别聚焦于左值或右值:
either.left()
.map(x -> decodeSQLErrorCode(x)); // 只对Left值生效
如果 Either
是 Left
,则应用 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
后,常见操作有三类:
- 提取值
- 链式操作成功值
- 用函数处理异常
其他方法基本都是这三类的变体。
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
是简单通用的数据结构,包含两个等重要的组件(称为 left
和 right
):
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 库的核心功能。未涉及代数结构类(如 Monoid
、Semigroups
),因为它们不适合通用场景。
想深入了解?查阅 Javadoc 和 源码。可选模块(如 Guava/Scala 集成)也值得探索。
所有示例代码可在 GitHub 项目 中找到(Maven 项目,可直接导入运行)。