代码之家  ›  专栏  ›  技术社区  ›  mindas

Google集合中的惰性不可修改列表

  •  8
  • mindas  · 技术社区  · 14 年前

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

    令人惊讶的是, google-collections 没有什么可以提供的;虽然 LazyList from Apache Commons Collections

    an attempt 在google集合之上构建一些东西,但它似乎是不完整的(例如,不支持 size() ),过时(不使用1.0 final编译)并且需要一些外部类,但可以作为构建自己的类的良好起点。

    有人知道懒汉列表有什么好的实现吗?如果没有,您认为哪种选择更好:

    • 围绕Commons Collections LazyList编写我自己的包装器(包装器只会添加泛型,因此我不必到处强制转换,而只在包装器本身中);
    • 在上面写点什么 java.util.AbstractList ;

    欢迎提出任何其他建议。

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

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

    4 回复  |  直到 14 年前
        1
  •  5
  •   Kevin Bourrillion Gergely    14 年前

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

    是的,你可以笑。你也许应该。我。。。不要真的推荐这个。仍然可能比您当前正在执行的代码少。我刚测试过。。它起作用了。

        2
  •  4
  •   Grzegorz Oledzki    14 年前

    有一个项目向Apache commons集合添加了泛型特性:

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

    (带有泛型的公共集合)

        3
  •  4
  •   mindas    14 年前

    java.lang.Iterable<T> . 实现抛出 UnsupportedOperationException remove()

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

    很抱歉让你失望,如果这将是一个在类似情况下的人不可行的选择,非常感谢的想法。

        4
  •  2
  •   Dimitris Andreou    14 年前

    PeterMaas you link的解决方案在我看来很不错-我强烈建议你用它来工作,而不是花时间重新设计这个。只要替换一下 Factory<T> 具有 Supplier<T> subList() ,并尝试将元素添加到子列表的边界之外,则不会得到 IndexOutOfBoundsException (正确的子列表应该这样做),但您将在列表中插入额外的元素。很可能您不需要子列表,因此最安全的方法是通过抛出 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)您不喜欢将null视为元素(很好!),以及(2)您的结构可能是稀疏的,而实际的ArrayList将是浪费的。