2010-04-22 51 views
8

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

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

我发现an attempt建立在谷歌的集合之上的东西,但它似乎是不完整的(如不支持size()),过时的,需要一些外部类(不与1.0最终编译),但也可以使用作为建立我自己的班级的一个很好的起点。

是否有人知道任何LazyList的良好实现?如果不是的话,你认为哪个选项更好:

  • 编写我自己的实现,基于谷歌集合ForwardingList,类似于Peter Maas做的;
  • 围绕Commons Collections LazyList编写我自己的包装器(包装器只会添加泛型,所以我不必到处施放,只能在包装器本身中使用);
  • 只需在java.util.AbstractList之上写点东西;

欢迎任何其他建议。

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

我得到了一个Lucene搜索结果(TopDocs),它基本上是一串指向Lucene文档的指针。我的搜索结果类将把这些指针作为输入,并返回由抽取和处理的Lucene文档组成的对象列表。通过将所有内容都包装进懒惰列表中,我希望确保在不必要的情况下不会进行昂贵的处理。

+0

你可以多说一点你真正想做的事情,所以我们可以理解为什么“懒惰列表”必然是正确的做法? – 2010-04-23 04:50:42

+0

@Kevin刚加了解释,谢谢! – mindas 2010-04-23 08:41:50

回答

4

我以不同的方式实际上已经解决了这个。我简单地实施java.lang.Iterable<T>,而不是懒惰和不可修改。该实现在remove()上抛出UnsupportedOperationException

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

对不起,如果这不会是一个在类似情况下的人可行的选择,并非常感谢这些想法。

2

您链接的彼得马斯的解决方案对我来说看起来不错 - 我强烈建议您使用这个解决方案,而不是花时间重塑这一点。只需将Factory<T>替换为Supplier<T>(包含在Google收藏中)。他的subList的实现也很聪明,虽然它有一些特殊的含义:如果你得到subList(),并尝试从subList的边界中添加一个元素,你将不会得到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(); 
     } 
     }); 

由于List<T>Map<Integer, T>或多或少代表相同的抽象数据类型,因为它从您的评论看来,(1)你不不要将空值视为元素(好!),(2)你的结构可能很稀疏,实际的ArrayList会浪费。

+0

我不喜欢Peter Maas的LazyList size(),它返回已经初始化的项目数量,而不是可能的可用项目数量。引用其Javadoc:“当调用{@link #get(int)}方法的索引大于列表大小 时,该列表将自动增大大小并从指定工厂返回一个新对象。 我希望有这个抽象,这样子类将被迫提供列表大小,因为在通用实现中可能不可能知道它。是的,我也需要子列表支持。 – mindas 2010-04-23 09:40:31

+0

@mindas,如果这是阻止您使用实现的功能,我建议您通过采用具有兼容许可证的最佳驱动器并根据需要更改大小来推出自己的产品。 – Yishai 2010-04-23 18:14:38

4

有它增加泛型功能捐赠给Apache commons-collections提供项目:

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

(共享的集合与泛型)

+0

感谢您的支持!然而,我却意识到公共收藏遭受同样大小的问题(请参阅我对Dimitris的评论)。但是,这可能对其他人有用。 – mindas 2010-04-23 14:08:47

5

谷歌收藏和番石榴的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(); 
    } 
    }; 
} 

是的,你可以笑。你可能应该。我......并不真的推荐这个。仍然可能比你现在正在做的更少的代码。我只是测试它..它的工作原理。

+0

谢谢凯文!我仍然坚持反对使用番石榴,主要是因为它没有最终确定(基本上与没有公开Maven回购的原因相同)。至于你的解决方案......我猜这甚至不会引起一个功能爱好者的眉毛,但是一旦我把它放进去,我肯定会在我的下一个忏悔中谈论很多! – mindas 2010-04-23 20:44:06

+2

已经有几个星期的二进制版本,上面提到的API都没有标记为Beta(我认为)。 – 2010-05-04 00:19:52