描述不可变的有序集合的类

问题描述 投票:0回答:4

我需要一些类/接口名称来描述不可变的有序集(按输入顺序,如

LinkedHashSet
)。我当然可以像这样使用这个类:

class Foo {
    public final Set<Long> frozenOrderedSet;

    public Foo(List<Long> input) {
        frozenOrderedSet = Collections.unmodifiableSet(new LinkedHashSet(input));
    }
}

但这并不能澄清我的方法。我想向阅读源代码的每个人明确表示,该集合是不可修改且唯一的,同时使用

for(Long l : set){}
保持其顺序。

java unordered-set unmodifiable
4个回答
13
投票

Guava 的 ImmutableSet 提供

a high-performance, immutable Set with reliable, user-specified iteration order.
还有像 ImmutableSortedSet 这样的变体。


3
投票

最简单的方法是扩展 Set 来创建自定义的不可变 Set。

public CustomImmutableSet(){ return Collections.unmodifyingSet(new LinkedHashSet(输入)); }

这样,每个阅读源代码的人都会清楚该集合是不可修改且唯一的


0
投票

Bozho 有问题Java 不可变集合

不可修改的集合通常是只读视图(包装器) 其他收藏。您无法添加、删除或清除它们,但 底层集合可能会改变。

不可变集合根本无法更改 - 它们不会换行 另一个系列 - 他们有自己的元素。

这是番石榴的 ImmutableList 的引用

与 Collections.unmodifyingList(java.util.List) 不同, 这是一个仍然可以改变的单独集合的视图, ImmutableList 的实例包含它自己的私有数据,并且永远不会 改变。

所以,基本上,为了从 可变集合,您必须将其元素复制到新集合中,并且 禁止所有操作。

所以基本上你可以创建类

TreeSet
的子类并覆盖所有 :add、remove 等方法,以抛出一个异常,说明这是不可变的集合。此外,您还必须在此类中使用一个参数创建复制构造函数
TreeSet setToCopyFrom


0
投票

java.util.Collection
源内部实现了使用静态包范围内部类生成不可修改集合的方法。

您可以将这些类的实现从 JDK 中的源代码复制到您的包中并将其公开。然后,您可以在代码中使用类型说明符,明确声明集合不可修改、已排序等。

毫无疑问,JDK 开发人员选择不公开这些类型是有原因的,但我不知道它是什么。

从 JDK 修改代码

此代码来自 JDK 21,实现与 JDK 相同,但类被定义为公共的,因此可以从任何包中使用它们。

不可修改的集合.java

package org.example.unmodifable;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.stream.Stream;

class UnmodifiableCollection<E> implements Collection<E>, Serializable {
    @java.io.Serial
    private static final long serialVersionUID = 1820017752578914078L;

    @SuppressWarnings("serial") // Conditionally serializable
    final Collection<? extends E> c;

    UnmodifiableCollection(Collection<? extends E> c) {
        if (c == null)
            throw new NullPointerException();
        this.c = c;
    }

    public int size() {
        return c.size();
    }

    public boolean isEmpty() {
        return c.isEmpty();
    }

    public boolean contains(Object o) {
        return c.contains(o);
    }

    public Object[] toArray() {
        return c.toArray();
    }

    public <T> T[] toArray(T[] a) {
        return c.toArray(a);
    }

    public <T> T[] toArray(IntFunction<T[]> f) {
        return c.toArray(f);
    }

    public String toString() {
        return c.toString();
    }

    public Iterator<E> iterator() {
        return new Iterator<>() {
            private final Iterator<? extends E> i = c.iterator();

            public boolean hasNext() {
                return i.hasNext();
            }

            public E next() {
                return i.next();
            }

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

            @Override
            public void forEachRemaining(Consumer<? super E> action) {
                // Use backing collection version
                i.forEachRemaining(action);
            }
        };
    }

    public boolean add(E e) {
        throw new UnsupportedOperationException();
    }

    public boolean remove(Object o) {
        throw new UnsupportedOperationException();
    }

    public boolean containsAll(Collection<?> coll) {
        return c.containsAll(coll);
    }

    public boolean addAll(Collection<? extends E> coll) {
        throw new UnsupportedOperationException();
    }

    public boolean removeAll(Collection<?> coll) {
        throw new UnsupportedOperationException();
    }

    public boolean retainAll(Collection<?> coll) {
        throw new UnsupportedOperationException();
    }

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

    // Override default methods in Collection
    @Override
    public void forEach(Consumer<? super E> action) {
        c.forEach(action);
    }

    @Override
    public boolean removeIf(Predicate<? super E> filter) {
        throw new UnsupportedOperationException();
    }

    @SuppressWarnings("unchecked")
    @Override
    public Spliterator<E> spliterator() {
        return (Spliterator<E>) c.spliterator();
    }

    @SuppressWarnings("unchecked")
    @Override
    public Stream<E> stream() {
        return (Stream<E>) c.stream();
    }

    @SuppressWarnings("unchecked")
    @Override
    public Stream<E> parallelStream() {
        return (Stream<E>) c.parallelStream();
    }
}

UnmodifyingSet.java

package org.example.unmodifable;

import java.io.Serializable;
import java.util.Set;

class UnmodifiableSet<E> extends UnmodifiableCollection<E>
        implements Set<E>, Serializable {
    @java.io.Serial
    private static final long serialVersionUID = -9215047833775013803L;

    UnmodifiableSet(Set<? extends E> s) {
        super(s);
    }

    public boolean equals(Object o) {
        return o == this || c.equals(o);
    }

    public int hashCode() {
        return c.hashCode();
    }
}

不可修改的SortedSet.java

package org.example.unmodifable;

import java.io.Serializable;
import java.util.Comparator;
import java.util.SortedSet;

public class UnmodifiableSortedSet<E>
        extends UnmodifiableSet<E>
        implements SortedSet<E>, Serializable {
    @java.io.Serial
    private static final long serialVersionUID = -4929149591599911165L;
    @SuppressWarnings("serial") // Conditionally serializable
    private final SortedSet<E> ss;

    UnmodifiableSortedSet(SortedSet<E> s) {super(s); ss = s;}

    public Comparator<? super E> comparator() {return ss.comparator();}

    public SortedSet<E> subSet(E fromElement, E toElement) {
        return new UnmodifiableSortedSet<>(ss.subSet(fromElement,toElement));
    }
    public SortedSet<E> headSet(E toElement) {
        return new UnmodifiableSortedSet<>(ss.headSet(toElement));
    }
    public SortedSet<E> tailSet(E fromElement) {
        return new UnmodifiableSortedSet<>(ss.tailSet(fromElement));
    }

    public E first()                   {return ss.first();}
    public E last()                    {return ss.last();}
}

测试用例

不可修改的SortedSetTest.java

package org.example.unmodifable;

import java.util.List;
import java.util.TreeSet;

public class UnmodifiableSortedSetTest {
    public static void main(String[] args) {
        UnmodifiableSortedSet<String> frozenAnimals = new UnmodifiableSortedSet<>(
                new TreeSet<>(List.of("dog", "cat", "lion", "cat"))
        );

        System.out.println(frozenAnimals);

        try {
            frozenAnimals.add("pigeon");
        } catch (UnsupportedOperationException e) {
            System.out.println("You can't modify the frozen list of animals.");
        }
    }
}

测试输出:

[cat, dog, lion]
You can't modify the frozen list of animals.
© www.soinside.com 2019 - 2024. All rights reserved.