Guava Collection Utils 与普通 Java 7

Guava Collection Utils vs. plain Java 7

我经常想使用 Guava 的集合实用程序编写代码,并发现自己在查看代码片段后用 Java 7 重写了代码,因为恕我直言,事实证明它更简洁,更易于阅读使用普通的旧 Java.

例如,使用 Guava 将对象列表放入具有从对象中获取的唯一索引的映射中时看起来像这样:

 List<A> myList = ...
 Map<A, B> mappings = Maps.uniqueIndex(myList, new Function<A, B>() {
     @Override
     public CustomerFinance apply(final A input) {
         return input.getB();
     }
 });

而在香草 Java 7 中它将是:

List<A> myList = ...
Map<A, B> mappings = new HashMap<>(myList.size());
for (A a : myList) {
    mappings.put(a.getB(), a);
}

Guava 中的映射有 5 个 LOC(甚至不计算 @Override 行)与普通 Java.

中的 4 个 LOC

为什么要在这里使用 Guava 实用程序?首先创建实用程序的动机是什么?我是否错过了 Guava 为我提供的一些额外好处?

您可能会争辩说,是的,在 LOC 方面并没有太大的收获。不过Guava风格比较functional.

transform函数可以传来传去used/reused.

 Function<A,B> map = new Function<A, B>() {
 @Override
 public CustomerFinance apply(final A input) {
     return input.getB();
 }

现在您可以传递地图并在不同的地方重复使用它。

Map<A, B> mappings = Maps.uniqueIndex(myList,map);
Map<C, D> mappings2 = Maps.uniqueIndex(myList,map);

但话又说回来,Guava 仅限于 Java 1.6 构造,这并没有为声明式风格提供最佳体验。

好消息是 Guava 中的 Function 是一个 functional interface,所以如果你移动到 Java 1.8,你可以从第一天开始使用 lambdas,你的代码将看起来像这样,

Map<A, B> mappings = Maps.uniqueIndex(myList, input-> input.getB());

Map<A, B> mappings = Maps.uniqueIndex(myList, A::getB);

当我在早于 8 的 Java 版本中编程时,我通常会创建一个关联的实用程序 class,以实体的形式命名,但采用复数形式,并将所有实用程序方法添加到其中。这样,我可以保持我的实体干净,并且可以访问大量实用方法。我没有系统地创建实用程序 class,而是仅在需要减少噪音时才创建。

public class MyEntity {
  private String text;
  public String getText() { return text; }
  public void setText (int text) { this.text = text; }
}

public final class MyEntities {
  private MyEntities() {}

  private enum MyEntityToString implements Function<MyEntity,String> {
    TEXT_GETTER {
      @Override public String apply(MyEntity input) { return input.getText(); }
    };
  }
  public static Function<MyEntity,String> textGetter() { return MyEntityToString.TEXT_GETTER; }
}

那么,使用起来就变得很简单了,需要的时候使用方法MyEntities.textGetter()就可以了。如果你只使用一次,是的,就 LOC 而言你会输,但如果你多次使用它,你就赢了。另外,如果你有一个错误,你只需要修复它一次,而不是找到所有的用法来修复它。

Am I missing some added benefit that Guava will provide me?

是的,你知道。

Guava 中有几个功能是您的翻译代码遗漏的 (JavaDoc of Maps#uniqueIndex):

  • null for values is prohibited (#)
  • 键的
  • null 被禁止(对于给定值,键函数不应该 return null
  • 禁止重复密钥(您不能意外地覆盖现有密钥)
  • 生成的映射是 不可变的

如果您也进行所有这些检查,那么您的代码应该比 Guavas 版本更长。

(#) 请注意,您的翻译版本目前也禁止 null,因为您在值对象上调用了 #getB()。这将导致像 Guava 中的 NullPointerException。如果您从其他地方获取密钥,例如 mappings.put(generateArtificalKey(), a);,那么 null 对于 Java 7 版本就可以了。


另一个优点是关键函数的代码更清晰。它可以很容易地移动到自己的 class 中并重复使用。一个例子可能是一个函数,它提取数据库实体的 id 以创建一个映射。但这更多的是一种意见,而不是事实,因为您的翻译代码(for 循环)也可以被提取并用于其他情况。