私は最近GUAVAのコレクションを見始めました。つまりImmutableList
、それは(ビルダーインスタンスなどで)かなり面倒に思えます。コレクションがどのように動作するかのより「自然な」方法を模倣するライブラリはありますか(scalaのhttp://www. scala-lang.org/api/current/index.html#scala.collection.immutable.Listは一例です)。追加/削除などを許可するが、不変性を維持し、おそらくパフォーマンスの目的で、古いリストの一部を再利用するものが欲しいです。
5 に答える
Goldman Sachs Collection ライブラリには ImmutableArrayList (およびその他の不変コレクション) があります。
ImmutableArrayList.java、メソッド newWith(T t) および newWithout(T t) を参照してください。
私があなたを正しく理解していれば、元のリスト構造を可能な限り再利用する新しいリストインスタンスを返す便利な追加/削除メソッドを持つ不変リストが必要です。次のようなことができます。
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()
ます。
これは特に素晴らしい実装ではないことに注意してください。新しい要素は、リストの末尾ではなく先頭に追加されます。しかし、おそらく、これでどこから始めればよいかがわかります。
Clojure には、そのような不変 (または永続的な)コレクションが含まれています。
簡単に言えば、新しい要素を追加または削除すると、新しいコレクションが返されます。これは一般に、 Trie 型のデータ構造を巧みに使用することで、古いコレクションの大部分を再利用します。
これらだけでは、そのままの Java で使用するには適していません。
Pure4jは、これら (および Clojure が提唱する不変/値ベースのスタイル) を Java 言語に移植する試みです。それはあなたが求めているものかもしれません。
免責事項: 私は Pure4J の開発者です