1. 概述

Vavr 虽然深度集成在 Java 生态中,但在实际开发中,我们经常需要将 Vavr 的数据结构转换为标准 Java 能直接处理的类型。

比如,某个方法返回的是 io.vavr.collection.List,但下游接口只接受 java.util.List —— 这时候,Java 与 Vavr 的互操作能力就显得尤为关键

本文将系统讲解如何 在 Vavr 数据结构与 Java 集合之间进行双向转换,涵盖常见集合、Stream、Optional 等场景,帮你避免踩坑,提升代码兼容性。


2. Vavr → Java 转换

Vavr 的 Value 接口是大多数功能组件的基类,所有 Vavr 集合都继承自它。✅

这个设计非常实用,因为 Value 接口内置了大量 toJavaXXX() 方法,能一键转成对应的 Java 标准类型

转换为 Java List

无论是 Vavr 的 List 还是 Stream,都能轻松转为 java.util.List

List<String> vavrStringList = List.of("JAVA", "Javascript", "Scala");
java.util.List<String> javaStringList = vavrStringList.toJavaList();
Stream<String> vavrStream = Stream.of("JAVA", "Javascript", "Scala");
java.util.List<String> javaStringList = vavrStream.toJavaList();

⚠️ 两个例子都用了 toJavaList(),底层会遍历元素创建新集合,时间复杂度 O(n)。

转换为 Java Map

Map 类型也一样简单:

Map<String, String> vavrMap = HashMap.of("1", "a", "2", "b", "3", "c");
java.util.Map<String, String> javaMap = vavrMap.toJavaMap();

其他 Java 类型支持

除了集合,Vavr 还原生支持转为 Java 8+ 的 StreamOptional

List<String> vavrList = List.of("Java");
Optional<String> optional = vavrList.toJavaOptional();
assertEquals("Java", optional.get());

📌 常用 toJavaXXX() 方法一览:

  • toJavaArray()
  • toJavaCollection()
  • toJavaList()
  • toJavaMap()
  • toJavaSet()
  • toJavaOptional() ✅ 特别适合对接 Spring 或 Java 8+ API
  • toJavaStream()
  • toJavaParallelStream()

🔗 完整 API 文档参考:Vavr Javadoc


3. Java → Vavr 转换

Vavr 所有集合类型都实现自 Traversable 接口,因此都提供一个统一的静态工厂方法:ofAll(Iterable)

只需要传入任意 Iterable,就能转成对应的 Vavr 集合。✅

从 java.util.List 转换

java.util.List<String> javaList = Arrays.asList("Java", "Haskell", "Scala");
List<String> vavrList = List.ofAll(javaList);

从 Java Stream 转换

java.util.stream.Stream<String> javaStream 
  = Arrays.asList("Java", "Haskell", "Scala").stream();
Stream<String> vavrStream = Stream.ofAll(javaStream);

⚠️ 注意:ofAll() 会消费 Stream(如果是无限流需小心),并生成不可变 Vavr 集合。


4. Java 集合视图(Views)

前面讲的 toJavaXXX() 都是深拷贝,会遍历所有元素创建新集合,性能开销 O(n)。

而 Vavr 提供了“视图”机制 —— 不复制数据,而是返回一个代理对象,所有操作委托到底层 Vavr 集合。性能为 O(1),更高效。✅

目前 Vavr 仅支持 List 的视图,提供两个方法:

方法 返回类型 是否可变
asJava() java.util.List ❌ 不可变
asJavaMutable() java.util.List ✅ 可变

不可变视图示例

@Test(expected = UnsupportedOperationException.class)
public void givenParams_whenVavrListConverted_thenException() {
    java.util.List<String> javaList 
      = List.of("Java", "Haskell", "Scala").asJava();
    
    javaList.add("Python"); // ❌ 抛异常
    assertEquals(4, javaList.size());
}

尝试修改会直接抛 UnsupportedOperationException

可变视图示例

@Test
public void givenParams_whenVavrListConvertedToMutable_thenRetunMutableList() {
    java.util.List<String> javaList = List.of("Java", "Haskell", "Scala")
      .asJavaMutable();
    javaList.add("Python"); // ✅ 成功添加
 
    assertEquals(4, javaList.size());
}

📌 适用场景:需要将 Vavr 集合传给第三方库(如 Jackson、Hibernate),又不想拷贝性能开销时,用 asJavaMutable() 是简单粗暴的解法。


5. Vavr 内部类型转换

除了与 Java 互转,Vavr 自身也支持 Value 类型之间的转换,非常灵活。

比如:有一个 List,想去重但保留插入顺序 —— 此时可用 toLinkedSet() 转成 LinkedHashSet

List<String> vavrList = List.of("Java", "Haskell", "Scala", "Java");
Set<String> linkedSet = vavrList.toLinkedSet();
assertEquals(3, linkedSet.size());
assertTrue(linkedSet instanceof LinkedHashSet);

📌 Value 接口还提供其他转换方法:

  • toSet()HashSet
  • toSortedSet()TreeSet
  • toList(), toVector(), toQueue()

🔗 完整方法列表见:Vavr Value Javadoc


6. 总结

本文系统梳理了 Vavr 与 Java 之间的互操作方式:

  • Vavr → Java:用 toJavaXXX() 方法,注意是深拷贝
  • Java → Vavr:统一用 ofAll(Iterable) 工厂方法
  • 高性能视图:优先考虑 asJava() / asJavaMutable(),避免不必要拷贝
  • Vavr 内部转换:利用 toXXX() 灵活切换集合类型

这些技巧在实际项目中非常实用,尤其是在接入老系统、混合使用 Java 与函数式风格时,能大幅降低集成成本。

💡 示例代码已托管至 GitHub:https://github.com/tech-tutorial/vavr-interop-demo


原始标题:Interoperability Between Java and Vavr