神秘的 Eclipse Collections API : forEachInBoth

有时候 API 一直在那里,等你去发现。

1. 听说过 forEachInBoth 吗

Eclipse Collections 提供了一个名为 forEachInBoth 的函数,只能在 ArrayIterate、ListIterate、RandomAccessListIterate 和 ArrayListIterate 这4个工具类中找到。

译注:Eclipse Collections 起源于2004年在高盛公司内部开发的一个名为 Caramel 的集合框架。自那以后,这个框架不断发展并在2012年开源成为 GitHub 中一个叫做 GS Collections 的项目,2015年被重新命名为 Eclipse Collections。Eclipse Collections 拥有内存优化的 Sets、Maps 和原始类型集合。

forEachInBoth 接受两个大小相同的 List 或 Array,按照特定索引对它们迭代,把两个列表中的元素传递给一个接受两个参数的 Procedure。

Eclipse Collections 中的 ListIterable 尚未支持此函数,也许是因为现在可以对两个列表执行 zip,然后用 forEach 或者 MutableList 的其他 API 完成操作。

2. 函数签名

forEachInBoth 在 ListIterate、RandomAccessListIterate 和 ArrayListIterate 中的函数签名非常相似,这里只展示 ListIterate 和 ArrayIterate 的签名。

ListIterate

public static <T1, T2> void forEachInBoth(        List<T1> list1,        List<T2> list2,        Procedure2<? super T1, ? super T2> procedure)

ArrayIterate

public static <T1, T2> void forEachInBoth(        T1[] objectArray1,        T2[] objectArray2,        Procedure2<? super T1, ? super T2> procedure)

3. 什么情况下推荐使用 forEachInBoth

下面的示例中,forEachInBoth 把两个独立的 List、Array 转成 Map。仅用 forEachInBoth 一个函数就能完成在 map 实例上调用 put 方法。

示例代码

@Testpublic void forEachInBothList(){    List<Integer> one =            Lists.mutable.with(1, 2, 3);    List<String> two =            Lists.mutable.with("One", "Two", "Three");    Map<Integer, String> map = Maps.mutable.empty();    ListIterate.forEachInBoth(one, two, map::put);    Assert.assertEquals(            Maps.mutable.with(1, "One", 2, "Two", 3, "Three"),            map);}

用 ArrayIterate 处理两个大小相同的数组非常方便。

4. zip 函数的用法

如果采用 zip 函数,可以用流式 API 调用 toMap,处理后的 List 转为 Map。然而,这里不对 Map 使用 forEach 或 each 迭代调用 Map.put。因为接下来要对 Pair 实例迭代,把 Pair 的两部分作为 key 和 value 传入。

示例代码

@Testpublic void zipList(){    MutableList<Integer> one =            Lists.mutable.with(1, 2, 3);    MutableList<String> two =            Lists.mutable.with("One", "Two", "Three");    MutableMap<Integer, String> map =            one.zip(two).toMap(Pair::getOne, Pair::getTwo);    Assert.assertEquals(            Maps.mutable.with(1, "One", 2, "Two", 3, "Three"),            map);}

上面的示例中,调用 zip 会创建一个临时列表。但由于没有其它地方引用,调用 toMap 后临时列表会被垃圾回收。也可以在 zip 之前调用 asLazy,这样可以避免创建临时列表。

MutableMap<Integer, String> map =        one.asLazy()                .zip(two)                .toMap(Pair::getOne, Pair::getTwo);

5. 什么时候使用 forEachInBoth、zip

forEachInBoth 主要优点在于它定义在 static 工具类中,可以直接处理 Java 数组和 java.util.List。如果需要将两个 JDK List 快速转成一个 Map,那么它可能正是你需要的。但是,由于 forEachInBoth 返回类型是 void,因此不能像用 zip 那样采用流式 API。大多数情况下,尤其是需要对结果执行多个操作时,用 zip 处理两个列表更合适。

如果发现 forEachInBoth 有合适的新用法,请在 GitHub 上创建 issue 让我们知道。当发现有更多好的用例出现,我们会为 ListIterable 添加 forEachInBoth。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注