9

我正在寻找一个通用的惰性不可修改列表实现的体面实现来包装我的搜索结果条目。任务中不可修改的部分很简单,因为它可以实现,Collections.unmodifiableList()所以我只需要整理出懒惰的部分。

令人惊讶的是,google-collections没有提供任何东西。而来自 Apache Commons Collections 的 LazyList不支持泛型。

我发现尝试在 google-collections 之上构建一些东西,但它似乎不完整(例如不支持size())、过时(不使用 1.0 final 编译)并且需要一些外部类,但可以用作一个好的开始点建立我自己的班级。

有人知道 LazyList 有什么好的实现吗?如果不是,您认为哪个选项更好:

  • 根据 google-collections ForwardingList 编写我自己的实现,类似于 Peter Maas 所做的;
  • 围绕 Commons Collections LazyList 编写我自己的包装器(包装器只会添加泛型,所以我不必在任何地方强制转换,而只需在包装器本身中);
  • 只需在上面写一些东西java.util.AbstractList

欢迎任何其他建议。

编辑:解释为什么我需要一个惰性列表。

我有一个 Lucene 搜索结果 (TopDocs),它基本上是一堆指向 Lucene 文档的指针。我的搜索结果类会将这些指针作为输入并返回一个对象列表,这些对象由提取的和以其他方式处理的 Lucene 文档组成。通过将所有内容包装到惰性列表中,我想确保在不必要时不会进行昂贵的处理。

4

4 回答 4

5

Google-collections 和 Guava 的Lists.transform方法为您提供了您所寻求的懒惰。坚持Iterables.transform应该一样好。

但是,如果您还担心结果应该在第一次创建后被缓存,那么......现在,这是我想出的最好的,它不会很令人欣慰:

List<Supplier<ExpensiveResult>> suppliers =
    ImmutableList.copyOf(Lists.transform(keys,
        new Function<Key, Supplier<ExpensiveResult>>() {
          public Supplier<ExpensiveResult> apply(Key key) {
            return Suppliers.memoize(Suppliers.compose(
                myExpensiveFunction(),
                Suppliers.ofInstance(key)));
          }
        }));

return Lists.transform(suppliers, ThisClass.<ExpensiveResult>supplyFunction());

 . . . 

private static <T> Function<Supplier<T>, T> supplyFunction() {
  return new Function<Supplier<T>, T>() {
    public T apply(Supplier<T> supplier) {
      return supplier.get();
    }
  };
}

是的,你可以笑。你可能应该。我……真的不推荐这个。仍然可能比您当前正在做的代码更少。我刚刚测试了它..它有效。

于 2010-04-23T18:10:50.590 回答
4

有一个项目将泛型特性添加到 Apache commons-collections:

http://sourceforge.net/projects/collections/

(Commons-collections with Generics)

于 2010-04-23T10:04:06.033 回答
4

我实际上以不同的方式解决了这个问题。我没有经历懒惰和不可修改,而是简单地实现了java.lang.Iterable<T>. 实现抛出UnsupportedOperationExceptionremove()

我不得不稍微修改一些其他代码部分,放弃一些东西,但我相信这是最好的选择。Iterable允许将其放在 foreach 循环中。

如果这对于处于类似情况的人来说不是一个可行的选择,很抱歉让您失望,非常感谢您的想法。

于 2010-04-23T16:47:56.383 回答
2

您链接的 Peter Maas 的解决方案对我来说看起来不错 - 我强烈建议您使用它,而不是花时间重新发明它。只需替换Factory<T>Supplier<T>(包含在谷歌收藏中)。他对 subList 的实现也很聪明,尽管它有一些特殊的含义:如果你得到 a subList(),并尝试在 subList 的边界之外添加一个元素,你将不会得到 a IndexOutOfBoundsException(作为正确的 subList 应该做的),但是您将在列表中插入额外的元素。很有可能你不需要子列表,所以最安全的方法是通过抛出UnsupportedOperationException(或构造一个 LazyList 来实现该方法,该方法具有一个额外的标志,表明它是否允许通过get()超出其大小的调用来增长:如果它由创建subList,则它不是)。

size() 支持(自动,ForwardingList本身)。

更新:请注意,正如凯文所说,你没有解释为什么这样的东西真的是你需要的。此外,也许您可​​能想考虑这样的事情是否适用:

final Supplier<T> supplier = ...;
Map<Integer, T> graphs = new MapMaker()
   .makeComputingMap(
       new Function<Integer, T>() {
         public T apply(Integer index) {
           return supplier.get();
         }
       });

由于或多或少代表相同的抽象数据类型,并且从您的评论中可以看出(1)您不喜欢将空值视为元素(好!),以及(2)您的结构可能是稀疏的List<T>Map<Integer, T>实际的 ArrayList 将是浪费的。

于 2010-04-22T21:19:18.517 回答