3

我最近开始查看 GUAVA 的集合,ImmutableList这似乎相当麻烦(使用构建器实例等)。是否有一个库可以模仿集合应该如何表现的更“自然”方式(scala 的http://www. scala-lang.org/api/current/index.html#scala.collection.immutable.List就是一个例子)。我想要一些允许添加/删除等但保留不变性的东西,并且可能出于性能的目的,重用旧列表的一部分。

4

5 回答 5

3

Goldman Sachs Collection 库中有一个 ImmutableArrayList(和其他不可变集合)

请参阅ImmutableArrayList.java方法 newWith(T t) 和 newWithout(T t)

于 2014-01-13T10:05:47.600 回答
1

如果我理解正确,您需要一个不可变列表,该列表具有方便的添加/删除方法,这些方法返回尽可能多地重用原始列表结构的新列表实例。你可以这样做:

public abstract class ImmutableList<T> implements Iterable<T> {
    /**
     * Adds an element to the head of the list, returning the new list.
     *
     * @param o The element to be added to the list.
     * @return The list consisting of the element <var>o</var> followed by
     *         this list.
     */
    public final ImmutableList<T> add(final T o) {
        return new Node<>(o, this);
    }

    /**
     * Removes the element <var>o</var> resulting in a new list which
     * is returned to the caller.
     *
     * @param o The object to be removed from the list.
     * @return A list consisting of this list with object <var>o</var> removed.
     */
    public abstract ImmutableList<T> remove(final T o);

    public abstract boolean isEmpty();
    public abstract int size();

    public abstract boolean contains(final T o);

    private ImmutableList() {}

    /**
     * Returns a "standard" enumeration over the elements of the list.
     */
    public Iterator<T> iterator() {
        return new NodeIterator<>(this);
    }

    /**
     * The empty list.  Variables of type ImmutableList should be
     * initialised to this value to create new empty lists.
     */
    private static final ImmutableList<?> EMPTY = new ImmutableList<Object>() {
        @Override
        public ImmutableList<Object> remove(final Object o) {
            return this;
        }

        @Override
        public boolean isEmpty() {
            return true;
        }

        @Override
        public int size() {
            return 0;
        }

        @Override
        public boolean contains(final Object o) {
            return false;
        }
    };

    @SuppressWarnings("unchecked")
    public static <T> ImmutableList<T> empty() {
        return (ImmutableList<T>)EMPTY;
    }

    public static <T> ImmutableList<T> create(final T head) {
        return new Node<>(head, ImmutableList.<T>empty());
    }

    static class Node<T> extends ImmutableList<T> {
        private final int _size;

        private Node(final T element, final ImmutableList<T> next) {
            _element = element;
            _next = ArgumentHelper.verifyNotNull(next, "next");
            _size = next.size() + 1;
        }

        public ImmutableList<T> remove(final T old) {
            if (_element == old) {
                return _next;
            }
            else {
                final ImmutableList<T> n = _next.remove(old);
                if (n == _next) {
                    return this;
                }
                else {
                    return new Node<>(_element, n);
                }
            }
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public int size() {
            return _size;
        }

        @Override
        public boolean contains(final T o) {
            return Objects.equals(_element, o) || _next.contains(o);
        }

        private final T _element;
        private final ImmutableList<T> _next;
    }

    private class NodeIterator<T> implements Iterator<T> {
        private ImmutableList<T> _current;

        private NodeIterator(final ImmutableList<T> head) {
            _current = ArgumentHelper.verifyNotNull(head, "head");
        }

        public boolean hasNext() {
            return !_current.isEmpty();
        }

        public T next() {
            final T result = ((Node<T>)_current)._element;
            _current = ((Node<T>)_current)._next;
            return result;
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}

对于此实现,通过将项目添加到ImmutableList.empty().

请注意,这不是一个特别出色的实现;新元素被附加到列表的开头,而不是结尾。但也许这会让你知道从哪里开始。

于 2013-11-14T15:37:51.663 回答
0

您的要求表明您误解了这些工具的用途。不可变列表始终需要构建器,因为在调用构造器后它不能更改。这就是不可变对象的全部目的。他们永远不会改变。没有“设置阶段”。

如果您不需要,只需将现有列表包装在Collections.unmodifiableList().

当然,缺点是有人可能会保留对原始列表的引用并对其进行修改。或者黑客可能会窥探包装器,获取底层列表并开始对其进行处理。

于 2013-11-14T15:31:43.733 回答
0

Clojure 包含这样的不可变(或持久)集合

简而言之,添加或删除新元素会返回一个新集合,它通常通过巧妙地使用 Trie 类型的数据结构重用旧集合的大部分。

就其本身而言,它们不适合在纯 Java 中使用。

Pure4j尝试将这些(以及 Clojure 提倡的基于不可变/基于值的风格)移植到 Java 语言。这可能是你所追求的。

免责声明:我是 Pure4J 的开发者

于 2015-11-06T14:02:44.237 回答
-1

不可变的意思是不变的,所以答案是否定的。你不能改变一个不可变的列表(哇!)。只要您只想使用一些内容初始化列表并将其保留,列表实用程序附带的构建器就很好,因此我建议您查看应用程序的架构。

关于旧列表的重用部分 - 如果列表是可变的,那么,通过改变它,您将冒着当前列表的状态不变性的风险。但是,如果实例都是不可变的,那么您实际上确实参考了前面的列表,因为您可以重复使用它的部分,只要它不改变,并且不可变的项目永远不会改变。

于 2013-11-14T15:34:20.150 回答