簡體   English   中英

Java:“缺點”列表中的項目

[英]Java: “cons” an item to a list

我有一個Item ,它有一個方法List<Item> getChildren() (返回一個不可變列表),對於我擁有的每個項目,我需要創建一個項目列表,后跟其子項。

什么是最快的方式“ 利弊 ”(在Lisp中/計划的意義上)我的項目創建一個新的不可變列表? 我當然可以做到以下幾點,但這似乎是錯誤的/浪費的:

public List<Item> getItemAndItsChildren(Item item)
{
    if (item.getChildren.isEmpty())
        return Collections.singletonList(item);
    else
    {
        // would rather just "return cons(item, item.getChildren())"
        // than do the following -- which, although straightforward,
        // seems wrong/wasteful.
        List<Item> items = new ArrayList<Item>();
        items.add(item);
        items.addAll(item.getChildren());
        return Collections.unmodifiableList(items);
    }
}

我會改變我的要求。 在大多數情況下,您的界面中不需要ListIterable可以很好地完成。 這是方法:

public Iterable<Item> getItemWithChildren(Item item)    {
    return Iterables.unmodifiableIterable(
        Iterables.concat(
            Collections.singleton(item),
            item.getChildren()
        )
    );
}

這是縮短版本(使用靜態導入):

return unmodifiableIterable(concat(singleton(item), item.getChildren()));

通過將head元素連接到可能在其他列表之間共享的尾部來創建新的不可變列表的能力需要單鏈接列表實現。 Java沒有提供開箱即用的任何東西,所以你的ArrayList解決方案就像任何東西一樣好。

假設這些列表是短暫的並且列表中沒有數萬個元素,它也會相對有效。 如果這樣做,並且如果此操作占用了大部分執行時間 ,那么實施您自己的單鏈表可能是值得的。

我的一個改進是提高現有效率:構建一個容量大的新列表(1 +舊列表的大小)。

你不應該特殊情況下沒有孩子的物品。

public List<Item> getItemAndItsChildren(Item item)
{
    List<Item> items = new ArrayList<Item>();
    items.add(item);
    items.addAll(item.getChildren());
    return Collections.unmodifiableList(items);
}

此外,如果您希望使用非冗長的語言,那么Java是一個糟糕的選擇。 我相信你可以在Groovy和Scala中的代碼少得多的地方運行,它們都運行在JVM上。 (更不用說JRuby或Jython。)

聽起來你正在尋找像CompositeList這樣的東西,類似於Apache Commons的CompositeCollection 一個實現可能像這樣天真:

public class CompositeList<T> extends AbstractList<T>{
    private final List<T> first, second;

    public CompositeList(List<T> first, List<T> second) {
        this.second = second;
        this.first = first;
    }

    @Override
    public T get(int index) {
        if ( index < first.size() ) {
            return first.get(index);
        } else {
            return second.get(index - first.size());
        }
    }

    @Override
    public int size() {
        return first.size() + second.size();
    }
}

你可以像這樣使用它:

public List<Item> getItemAndItsChildren(Item item)
{
    return Collections.unmodifiableList( 
        new CompositeList<Item>(Collections.singletonList(item), item.getChildren()) );
}

但是有很多警告使得這樣的類難以使用......主要的問題是List接口本身不能強制它是不可修改的。 如果您打算使用這樣的東西,您必須確保此代碼的客戶端永遠不會修改這些代碼!

我用這些。 (使用番石榴的ImmutableList和Iterables)

/** Returns a new ImmutableList with the given element added */
public static <T> ImmutableList<T> add(final Iterable<? extends T> list, final T elem) {
    return ImmutableList.copyOf(Iterables.concat(list, Collections.singleton(elem)));
}

/** Returns a new ImmutableList with the given elements added */
public static <T> ImmutableList<T> add(final Iterable<? extends T> list, final Iterable<? extends T> elems) {
    return ImmutableList.copyOf(Iterables.concat(list, elems));
}

/** Returns a new ImmutableList with the given element inserted at the given index */
public static <T> ImmutableList<T> add(final List<? extends T> list, final int index, final T elem) {
    return ImmutableList.copyOf(Iterables.concat(list.subList(0, index), Collections.singleton(elem), list.subList(index, list.size())));
}

/** Returns a new ImmutableList with the given element inserted at the given index */
public static <T> ImmutableList<T> add(final List<? extends T> list, final int index, final Iterable<?extends T> elems) {
    return ImmutableList.copyOf(Iterables.concat(list.subList(0, index), elems, list.subList(index, list.size())));
}

但它們都不是有效的。

在項目列表中添加/提交項目的示例:

ImmutableList<String> letters = ImmutableList.of("a", "b", "c");
add(letters, 0, "d");

對於更高效的不可變/持久集合,你應該像@eneveu指出的那樣,查看pcollections,盡管我不知道該庫的質量是什么。

pcollections是一個你可能感興趣的持久Java集合庫。我前一段時間給它添加了書簽,還沒有使用它,但項目似乎相對活躍。

如果你想使用Guava,你可以使用Lists.asList返回的不可修改的視圖(E first,E [] rest) 它適用於數組,其主要目標是簡化var-args方法的使用。 但我認為沒有理由你不能在你的情況下使用它:

public List<Item> getItemAndItsChildren(Item item) {
    return Lists.asList(item, item.getChildren().toArray());
}

返回的List是一個不可修改的視圖,但如果修改了源數組,它可能會更改。 在您的情況下,這不是問題,因為getChildren()方法返回不可變列表。 即使它是可變的, toArray()方法也應該返回一個“安全”的數組 ......

如果你想要更安全,你可以這樣做:

public ImmutableList<Item> getItemAndItsChildren(Item item) {
    return ImmutableList.copyOf(Lists.asList(item, item.getChildren().toArray()));
}

請注意, Lists.asList()避免了不必要的ArrayList實例化,因為它是一個視圖。 此外,當子列表為空(與Collections.singletonList()類似,節省空間ImmutableList.of(E element)時, ImmutableList.copyOf()將委托給ImmutableList.of(E element) )。

您應該使用您將添加的確切數字來實例化您的列表,以便在添加更多內容時消除擴展副本。

List<Item> items = new ArrayList<Item>();

應該

List<Item> items = new ArrayList<Item>(item.getChildren() + 1);

否則你所做的就像你可以得到的慣用Java一樣。

另一件事是,您可能會考慮使用Guava及其ImmutableList實現而不是Collections.unmodifiableList()

Collections.unmodifiableList(java.util.List)不同,后者是一個仍然可以更改的單獨集合的視圖, ImmutableList的實例包含其自己的私有數據,並且永遠不會更改。 ImmutableList方便公共靜態最終列表(“常量列表”),還可以讓您輕松地為調用者提供給您的類的列表的“防御性副本”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM