Google Collections中的懒惰不可修改列表
我正在寻找一个通用的懒惰不可修改列表实现的一个不错的实现来包装我的搜索结果条目。 任务的不可修改部分很容易,因为它可以通过Collections.unmodifiableList()
实现,所以我只需要理清惰性部分。
令人惊讶的是, 谷歌collections品没有提供任何东西; 而来自Apache Commons Collections的LazyList不支持generics。
我发现尝试在google-collections之上构建一些东西,但它似乎是不完整的(例如,不支持size()
),过时的(不用1.0最终编译)并需要一些外部类,但可以用作建立自己的课程的一个很好的起点。
是否有人知道LazyList的任何良好实现? 如果没有,您认为哪个选项更好:
- 编写我自己的实现,基于google-collections ForwardingList,类似于Peter Maas所做的;
- 在Commons Collections LazyList周围编写我自己的包装器(包装器只会添加generics,所以我不需要在任何地方进行转换,只能在包装器本身中进行转换);
- 只需在
java.util.AbstractList
上面写一些东西;
欢迎任何其他建议。
编辑:解释为什么我需要一个懒惰的列表。
我有一个Lucene搜索结果(TopDocs),它基本上是Lucene文档的一堆指针。 我的搜索结果类将这些指针作为输入并返回由提取的和以其他方式处理的Lucene文档组成的对象列表。 通过将所有内容包装到一个惰性列表中,我希望确保在不必要时不进行昂贵的处理。
Google-collections和Guava的Lists.transform
方法为您提供了所寻求的懒惰。 坚持Iterables.transform
应该同样好。
但是,如果您还担心结果应该在首次创建时缓存,那么……现在,这是我想出的最好的结果,并且它不会非常令人欣慰:
List> suppliers = ImmutableList.copyOf(Lists.transform(keys, new Function>() { public Supplier apply(Key key) { return Suppliers.memoize(Suppliers.compose( myExpensiveFunction(), Suppliers.ofInstance(key))); } })); return Lists.transform(suppliers, ThisClass. supplyFunction()); . . . private static Function, T> supplyFunction() { return new Function, T>() { public T apply(Supplier supplier) { return supplier.get(); } }; }
是的,你可以笑。 你可能应该这样做。 我……真的不推荐这个。 代码可能仍然少于您目前所做的代码。 我只是测试了它..它的工作原理。
有一个项目在Apache commons-collections中添加了Genericsfunction:
http://sourceforge.net/projects/collections/
(与generics的共享集合)
我实际上已经以不同的方式解决了这个问题。 我简单地实现了java.lang.Iterable
,而不是通过懒惰和不可修改的方式。 该实现在remove()
上抛出UnsupportedOperationException
。
我不得不稍微修改一些其他代码部分,放弃一些东西,但我相信这是最好的选择。 Iterable
允许它放在foreach循环上。
很抱歉让人失望,如果对于类似情况的人来说这不是一个可行的选择,并非常感谢这些想法。
您链接的Peter Maas的解决方案对我来说很好 – 我强烈建议您使用它,而不是花时间重新发明这一点。 只需将Factory
替换为Supplier
(包含在google集合中)。 他对subList的实现也很聪明,虽然它有一些特殊的含义:如果你得到一个subList()
,并尝试从subList的边界中添加一个元素,你将不会得到一个IndexOutOfBoundsException
(作为一个正确的subList应该do),但你会在列表中插入额外的元素。 可能的情况是你不需要子列表,所以最安全的方法是通过抛出UnsupportedOperationException
来实现该方法(或者构造一个LazyList,它有一个额外的标志,它是否允许通过超过其大小的get()
调用来增长:如果它由subList
创建,然后它不是)。
支持size()
(由ForwardingList
本身自动支持)。
更新:请注意,正如凯文所说,你没有解释为什么这样的东西真的是你需要的。 此外,也许您可能想要考虑这样的事情是否适用:
final Supplier supplier = ...; Map graphs = new MapMaker() .makeComputingMap( new Function() { public T apply(Integer index) { return supplier.get(); } });
由于List
和Map
或多或少代表相同的抽象数据类型,并且因为它从你的注释中看来(1)你不喜欢将null视为元素(好!),并且(2)你的结构可能是稀疏的,实际的ArrayList会浪费。