【问题标题】:Fluently adding to a Collection (add and return the value)流畅地添加到集合(添加并返回值)
【发布时间】:2016-10-17 14:49:08
【问题描述】:

一次又一次,我发现自己处于想要使用一个值的情况,同时将它添加到一个集合中,例如:

List<String> names = new ArrayList<>();
person1.setName(addTo(names, "Peter"));
person2.setName(addTo(names, "Karen"));

(注意:使用 java.util.Collection.add(E) 当然不起作用,因为它返回一个布尔值。)

当然,自己编写一个实用方法很容易,例如:

public static <E> E addTo(Collection<? super E> coll, E elem) {
    coll.add(elem);
    return elem;
}

但是在 JavaSE、Commons Collections、Guava 或其他一些“标准”库中真的没有类似的东西吗?

【问题讨论】:

  • 番石榴永远不会成为这样的“帮手”。公地,也许吧。
  • @shmosel:我同意,但也许番石榴可以有不同的形式,例如作为一个包装器,类似于他们的 FluentIterable。
  • 尝试同时做两件事不是一个坏习惯吗?一个名为 addToCollectionAndReturnValue 的方法对我来说并不合适。当您在这篇文章中编写解决方案时,我也不明白您为什么要为此寻找“标准”解决方案。
  • @Wesley:我确实看到了一些缺点,但个人认为这不是一个坏习惯,因为它避免了每次都写两行,创建大量局部变量,这很容易导致错误和难以阅读的代码。还要考虑一下,比如java.util.Map也有一个fluent方法“V put(K key, V value)”。
  • 通常人们要求的是返回集合的东西,所以可以像coll.add(a).add(b).add(c);这样链接调用。另请注意,Map.put() 返回的是 previous 值,而不是参数。

标签: java collections guava apache-commons


【解决方案1】:

如果您使用Eclipse Collections,以下将起作用:

MutableList<String> names = Lists.mutable.empty();
person1.setName(names.with("Peter").getLast());
person2.setName(names.with("Karen").getLast());

with 方法返回要添加的集合,因此您可以根据需要轻松地进行链式添加。通过在MutableList(扩展java.util.List)上调用with 之后使用getLast,您将获得刚刚添加的元素。

注意:我是 Eclipse Collections 的提交者。

【讨论】:

    【解决方案2】:

    这在我看来是一个非常奇怪的模式。像person1.setName(addTo(names, "Peter")) 这样的行似乎是倒置的,很难正确解析:

    为现有的人员对象分配了一个名称,该名称将首先添加到名称列表中,名称为“Peter”。

    与(例如)person1.setName("Peter"); names.add(person1.getName()); 对比:

    使“Peter”成为现有人员对象的名称,然后将该名称添加到名称列表中。

    我很欣赏这是两个陈述而不是一个,但相对于您提出的不寻常语义而言,这是一个非常低的成本。后一种格式更容易理解,更容易重构,也更惯用。

    我愿意打赌,许多可能从您的 addTo() 方法中受益的场景还有其他问题,并且可以通过早期的不同重构得到更好的服务。


    问题的核心似乎是您试图表示一个复杂的数据类型 (Person),同时构建一个由这些对象的特定方面组成的不相关列表。一个可能更直接(并且仍然流畅)的选项是构造一个 Person 对象列表,然后转换该列表以提取您需要的值。考虑:

    List<Person> people = ImmutableList.of(new Person("Peter"), new Person("Karen"));
    List<String> names = people.stream().map(Person::getName).collect(toList());
    

    请注意,我们不再需要隔离的 person1person2 变量,现在 peoplenames 之间存在更直接的关系。根据您需要names 的内容,您可能完全可以避免构建第二个列表,例如与List.forEach()

    如果您还没有使用 Java 8,您仍然可以使用带有 Guava's functional utilities 的函数式语法。该页面上的警告也值得一读,即使在 Java-8 领域也是如此。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-02
      • 1970-01-01
      • 2017-04-06
      • 1970-01-01
      • 1970-01-01
      • 2019-06-18
      • 2012-10-01
      相关资源
      最近更新 更多