开发者

Any way to set max size of a collection?

开发者 https://www.devze.com 2023-02-14 17:05 出处:网络
is there any way to set 开发者_开发技巧maximum size of collection in Java?You can do this: List<X> list = Arrays.asList(new X[desiredSize]);

is there any way to set 开发者_开发技巧maximum size of collection in Java?


You can do this:

List<X> list = Arrays.asList(new X[desiredSize]);
// where X is any Object type (including arrays and enums,
// but excluding primitives)

The resulting list is modifiable, but not resizable (i.e. add(e) and remove(e) don't work, but set(index, e) does).

Reference:

  • Arrays.asList(T ...)

Or: using Guava, here's a static method that decorates an existing List with a maximum size

public static <T> List<T> setMaxSize(
    final List<T> input, final int maxSize){

    return new ForwardingList<T>(){

        @Override
        public boolean addAll(Collection<? extends T> collection){
            return standardAddAll(collection);
        }

        @Override
        public boolean addAll(int index, Collection<? extends T> elements){
            return standardAddAll(index, elements);
        }

        public boolean add(T e) {
            checkMaxSize();
            return delegate().add(e);
        }

        @Override
        public void add(final int index, final T e){
            checkMaxSize();
            delegate().add(index, e);
        }

        private void checkMaxSize(){
            if(size() >= maxSize){
                throw new UnsupportedOperationException("Maximum Size "
                    + maxSize + " reached");
            }
        }

        @Override
        protected List<T> delegate(){
            return input;
        }
    };
}

Since ForwardingXxx classes exist for all standard collection types, you can write yourself similar decorators for other collections as well.

Obviously this will only work if your client code uses the decorated collection. If you change the underlying collection you are screwed (just like the Collections.unmodifiableXXX methods)

Reference:

  • ForwardingList


ArrayBlockingQueue and LinkedBlockingQueue both support a maximum size. LinkedHashMap supports eviction of the oldest or least-recently-used items when reaching a maximum size.

What do you want it to do when the maximum size is reached?


Not with the java.util collections classes, but with any particular collection you could extend it, and override the .add() or .put() to your own ends. Something like this would work for a List:

public final boolean add(E e) {
    if (this.size() == MAX_SIZE){
        throw new IllegalStateException("List is already at maximum size of " + MAX_SIZE);
    }
    super.add(e);
}

JavaDoc says IllegalStateExeption is correct "if the element cannot be added at this time due to insertion restrictions".

Edit: As Stas Kurilin points out below, you'd have to be careful to override all the methods which could add something to the collection though, such as .addAll().

Edit 2: As Paŭlo Ebermann points out below, the correct response when an element is not added is to throw an exception.


You would have to implement your own Collection. Furthermore, Your notion of max size isn't completely defined. For instance, do you wish to prevent new items from being added? Drop off the oldest item? The newest item? Max size is an attribute, not a behavior. You need to define the behavior part if you were to implement this.


Super easy to create your own class that extends the Collection. I just did this for my own situation, extending HashSet:

import java.util.HashSet;

public class LimitedHashSet<E> extends HashSet<E> {
    private static final long serialVersionUID = -23456691722L;
    private final int limit;

    public LimitedHashSet(int limit) {
        this.limit = limit;
    }

    @Override
    public boolean add(E object) {
        if (this.size() > limit) return false;
        return super.add(object);
    }

} 


If you don't mind an external library, you can Guava's EvictingQueue.

Example by srigalamilitan:

Queue<String> evictingQueue= EvictingQueue.create(10);
String message="This Is Evicting Queue ";

for (int i = 1; i <= 15; i++) {
    evictingQueue.add(message + i);
    System.out.println("EvictingQueue size: " + evictingQueue.size());
}

System.out.println("Poll Queue Evicting");
while(!evictingQueue.isEmpty()){
    println(evictingQueue.poll());
}

prints:

This Is Evicting Queue 6
This Is Evicting Queue 7
This Is Evicting Queue 8
This Is Evicting Queue 9
This Is Evicting Queue 10
This Is Evicting Queue 11
This Is Evicting Queue 12
This Is Evicting Queue 13
This Is Evicting Queue 14
This Is Evicting Queue 15


Most general-purpose collections in the standard library DO NOT have a hard capacity - just a minimum initial allocation. The only exception I Can think off the top of my head is LinkedBlockingQueue. Other libraries have other bounded collections, like an LRUCache.

It should be fairly straightforward to create your own wrapper, if that is useful to you.


you can set the initial capacity of some collections. I dont think you can set the max size.

You can build that logic into your domain classes (business logic) to enforce max size. Or you could create a subclass....


If you mean "is there a method on the Collection interface (or standard implementations of it) where you can set the size the answer is no. Can you write (or extend) a class to have a maximum size than you certainly can.


Maybe I had a comparable case, as I wanted to "resize" a collection of objects, which I retrieved through two steps:

  • First step retrieved Collection of N determined items through sql query (ROWNUM did the job).

  • Second step validating the result collection to get finally another collection with undetermined size (may be < or = the size of all sql-retrieved elements).

So in turn to get again a collection of exactly N determined objects from this "CollectionOfValidatedObjects", I did the following:

public Collection<Object> determineSomeElements(int maxSize){    


     Collection<Object> returnValues = new ArrayList<Object>();

      // the initial collection with all retrieved validated elements
     Collection<Object> myValidatedCollection = getValidatedCollection();

     Iterator<Object> it = myValidatedCollection.iterator();

     
     // iterate and add a condition with the passed size
     while(it.hasNext() && returnValues.size() < maxSize) {

           returnValues.add(it.next); }    

     }

}


Here is my own code for an ArrayList with a maximum size, build from Matthew Gilliard's answer. It overrides all three constructors from ArrayList, and also overrides .AddAll().

import java.util.ArrayList;
import java.util.Collection;

public class MaxedArrayList<E> extends ArrayList<E> {
    final int MAXSIZE;

    public MaxedArrayList(int initialCapacity, final int MAXSIZE) {
        super(initialCapacity);
        this.MAXSIZE = MAXSIZE;
    }

    public MaxedArrayList(final int MAXSIZE) {
        super();
        this.MAXSIZE = MAXSIZE;
    }

    public MaxedArrayList(Collection<? extends E> c, final int MAXSIZE) {
        super(c);
        this.MAXSIZE = MAXSIZE;
        sizeCheck();
    }

    private boolean sizeCheck() {
        //returns true if operation is legal.
        return (size() <= MAXSIZE);
    }

    private boolean sizeCheck(int deltaElements) {
        if (deltaElements < 0) throw new IllegalArgumentException();
        //returns true if operation is legal.
        return (size() + deltaElements <= MAXSIZE);
    }

    @Override
    public void add(int index, E element) throws IllegalStateException {
        if (!sizeCheck()) throw throwException();
        super.add(index, element);
    }

    @Override
    public boolean addAll(Collection<? extends E> c) throws IllegalStateException {
        if (!sizeCheck(c.size())) throw throwException();
        return (super.addAll(c));
    }

    private IllegalStateException throwException() {
        return new IllegalStateException("Request is over MaxArrayList max size. Elements not added.");
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消