Define a fixed-size list in Java

JavaListCollections

Java Problem Overview


Is it possible to define a list with a fixed size that's 100? If not why isn't this available in Java?

Java Solutions


Solution 1 - Java

This should do it if memory serves:

List<MyType> fixed = Arrays.asList(new MyType[100]);

Solution 2 - Java

A Java list is a collection of objects ... the elements of a list. The size of the list is the number of elements in that list. If you want that size to be fixed, that means that you cannot either add or remove elements, because adding or removing elements would violate your "fixed size" constraint.

The simplest way to implement a "fixed sized" list (if that is really what you want!) is to put the elements into an array and then Arrays.asList(array) to create the list wrapper. The wrapper will allow you to do operations like get and set, but the add and remove operations will throw exceptions.

And if you want to create a fixed-sized wrapper for an existing list, then you could use the Apache commons FixedSizeList class. But note that this wrapper can't stop something else changing the size of the original list, and if that happens the wrapped list will presumably reflect those changes.


On the other hand, if you really want a list type with a fixed limit (or limits) on its size, then you'll need to create your own List class to implement this. For example, you could create a wrapper class that implements the relevant checks in the various add / addAll and remove / removeAll / retainAll operations. (And in the iterator remove methods if they are supported.)

So why doesn't the Java Collections framework implement these? Here's why I think so:

  1. Use-cases that need this are rare.
  2. The use-cases where this is needed, there are different requirements on what to do when an operation tries to break the limits; e.g. throw exception, ignore operation, discard some other element to make space.
  3. A list implementation with limits could be problematic for helper methods; e.g. Collections.sort.

Solution 3 - Java

Yes,

Commons library provides a built-in FixedSizeList which does not support the add, remove and clear methods (but the set method is allowed because it does not modify the List's size). In other words, if you try to call one of these methods, your list still retain the same size.

To create your fixed size list, just call

List<YourType> fixed = FixedSizeList.decorate(Arrays.asList(new YourType[100]));

You can use unmodifiableList if you want an unmodifiable view of the specified list, or read-only access to internal lists.

List<YourType> unmodifiable = java.util.Collections.unmodifiableList(internalList);

Solution 4 - Java

Yes. You can pass a java array to Arrays.asList(Object[]).

List<String> fixedSizeList = Arrays.asList(new String[100]);

You cannot insert new Strings to the fixedSizeList (it already has 100 elements). You can only set its values like this:

fixedSizeList.set(7, "new value");

That way you have a fixed size list. The thing functions like an array and I can't think of a good reason to use it. I'd love to hear why you want your fixed size collection to be a list instead of just using an array.

Solution 5 - Java

Typically an alternative for fixed size Lists are Java arrays. Lists by default are allowed to grow/shrink in Java. However, that does not mean you cannot have a List of a fixed size. You'll need to do some work and create a custom implementation.

You can extend an ArrayList with custom implementations of the clear, add and remove methods.

e.g.

import java.util.ArrayList;

public class FixedSizeList<T> extends ArrayList<T> {

    public FixedSizeList(int capacity) {
        super(capacity);
        for (int i = 0; i < capacity; i++) {
            super.add(null);
        }
    }

    public FixedSizeList(T[] initialElements) {
        super(initialElements.length);
        for (T loopElement : initialElements) {
            super.add(loopElement);
        }
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException("Elements may not be cleared from a fixed size List.");
    }

    @Override
    public boolean add(T o) {
        throw new UnsupportedOperationException("Elements may not be added to a fixed size List, use set() instead.");
    }

    @Override
    public void add(int index, T element) {
        throw new UnsupportedOperationException("Elements may not be added to a fixed size List, use set() instead.");
    }

    @Override
    public T remove(int index) {
        throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
    }

    @Override
    public boolean remove(Object o) {
        throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
    }

    @Override
    protected void removeRange(int fromIndex, int toIndex) {
        throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
    }
}

Solution 6 - Java

Create an array of size 100. If you need the List interface, then call Arrays.asList on it. It'll return a fixed-size list backed by the array.

Solution 7 - Java

If you want some flexibility, create a class that watches the size of the list.

Here's a simple example. You would need to override all the methods that change the state of the list.

public class LimitedArrayList<T> extends ArrayList<T>{
    private int limit;

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

    @Override
    public void add(T item){
        if (this.size() > limit)
            throw new ListTooLargeException();
        super.add(item);
    }

    // ... similarly for other methods that may add new elements ...

Solution 8 - Java

You can define a generic function like this:

@SuppressWarnings("unchecked")
public static <T> List<T> newFixedSizeList(int size) {
    return (List<T>)Arrays.asList(new Object[size]);
}

And

List<String> s = newFixedSizeList(3);  // All elements are initialized to null
s.set(0, "zero");
s.add("three");  // throws java.lang.UnsupportedOperationException

Solution 9 - Java

This should work pretty nicely. It will never grow beyond the initial size. The toList method will give you the entries in the correct chronological order. This was done in groovy - but converting it to java proper should be pretty easy.

static class FixedSizeCircularReference<T> {
    T[] entries
    FixedSizeCircularReference(int size) {
        this.entries = new Object[size] as T[]
        this.size = size
    }
    int cur = 0
    int size
    void add(T entry) {
        entries[cur++] = entry
        if (cur >= size) {
            cur = 0
        }
    }
    List<T> asList() {
        List<T> list = new ArrayList<>()
        int oldest = (cur == size - 1) ? 0 : cur
        for (int i = 0; i < this.entries.length; i++) {
            def e = this.entries[oldest + i < size ? oldest + i : oldest + i - size]
            if (e) list.add(e)
        }
        return list
    }
}

FixedSizeCircularReference<String> latestEntries = new FixedSizeCircularReference(100)
latestEntries.add('message 1') 
// .....
latestEntries.add('message 1000') 
latestEntries.asList() //Returns list of '100' messages

Solution 10 - Java

If you want to use ArrayList or LinkedList, it seems that the answer is no. Although there are some classes in java that you can set them fixed size, like PriorityQueue, ArrayList and LinkedList can't, because there is no constructor for these two to specify capacity.

If you want to stick to ArrayList/LinkedList, one easy solution is to check the size manually each time.

public void fixedAdd(List<Integer> list, int val, int size) {
    list.add(val);
    if(list.size() > size) list.remove(0);
}

LinkedList is better than ArrayList in this situation. Suppose there are many values to be added but the list size is quite samll, there will be many remove operations. The reason is that the cost of removing from ArrayList is O(N), but only O(1) for LinkedList.

Solution 11 - Java

The public java.util.List subclasses of the JDK don't provide a fixed size feature that doesn't make part of the List specification.
You could find it only in Queue subclasses (for example ArrayBlockingQueue, a bounded blocking queue backed by an array for example) that handle very specific requirements.

In Java, with a List type, you could implement it according to two scenarios :

  1. The fixed list size is always both the actual and the maximum size.

It sounds as an array definition. So Arrays.asList() that returns a fixed-size list backed by the specified array is what you are looking for. And as with an array you can neither increase nor decrease its size but only changing its content. So adding and removing operation are not supported.

For example :

Foo[] foosInput= ...;
List<Foo> foos = Arrays.asList(foosInput);
foos.add(new Foo()); // throws an Exception
foos.remove(new Foo()); // throws an Exception

It works also with a collection as input while first we convert it into an array :

Collection<Foo> foosInput= ...;
List<Foo> foos = Arrays.asList(foosInput.toArray(Foo[]::new)); // Java 11 way
// Or
List<Foo> foos = Arrays.asList(foosInput.stream().toArray(Foo[]::new)); // Java 8 way

2) The list content is not known as soon as its creation. So you mean by fixed size list its maximum size.

You could use inheritance (extends ArrayList) but you should favor composition over that since it allows you to not couple your class with the implementation details of this implementation and provides also flexibility about the implementation of the decorated/composed.

With Guava Forwarding classes you could do :

import com.google.common.collect.ForwardingList;

public class FixedSizeList<T> extends ForwardingList<T> {

  private final List<T> delegate;
  private final int maxSize;

  public FixedSizeList(List<T> delegate, int maxSize) {
    this.delegate = delegate;
    this.maxSize = maxSize;
  }

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

  @Override public boolean add(T element) {
    assertMaxSizeNotReached(1);
    return super.add(element);
  }

  @Override public void add(int index, T element) {
    assertMaxSizeNotReached(1);
    super.add(index, element);
  }

  @Override public boolean addAll(Collection<? extends T> collection) {
    assertMaxSizeNotReached(collection.size());
    return super.addAll(collection);
  }

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

  private void assertMaxSizeNotReached(int size) {
    if (delegate.size() + size >= maxSize) {
      throw new RuntimeException("size max reached");
    }
  }

}

And use it :

List<String> fixedSizeList = new FixedSizeList<>(new ArrayList<>(), 3); 
fixedSizeList.addAll(Arrays.asList("1", "2", "3"));
fixedSizeList.add("4");  // throws an Exception

Note that with composition, you could use it with any List implementation :

List<String> fixedSizeList = new FixedSizeList<>(new LinkedList<>(), 3); 
//...

Which is not possible with inheritance.

Solution 12 - Java

You need either of the following depending on the type of the container of T elements you pass to the builder (Collection<T> or T[]):

  • In case of an existing Collection<T> YOUR_COLLECTION:

> java > Collections.unmodifiableList(new ArrayList<>(YOUR_COLLECTION)); >

  • In case of an existing T[] YOUR_ARRAY:

> java > Arrays.asList(YOUR_ARRAY); > Simple as that

Solution 13 - Java

To get a fixed-size list, you can simply use the Stream API. This will result in a fixed-size list :

    List<Integer> list = Arrays.stream(new int[100])
                            .boxed()
                            .collect(Collectors.toList());

Or the old-fashioned way, This will result in a fixed-size list that is backed by the specified array:

    List<Integer> list = Arrays.asList(new Integer[100]);

Solution 14 - Java

Yes is posible:

List<Integer> myArrayList = new ArrayList<>(100);

now, the initial capacity of myArrayList will be 100

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionfastcodejavaView Question on Stackoverflow
Solution 1 - JavaMcDowellView Answer on Stackoverflow
Solution 2 - JavaStephen CView Answer on Stackoverflow
Solution 3 - JavaArthur RonaldView Answer on Stackoverflow
Solution 4 - JavasnakileView Answer on Stackoverflow
Solution 5 - JavashamsView Answer on Stackoverflow
Solution 6 - JavadevelopmentalinsanityView Answer on Stackoverflow
Solution 7 - JavaJeremyView Answer on Stackoverflow
Solution 8 - Javauser4910279View Answer on Stackoverflow
Solution 9 - JavaBas KuisView Answer on Stackoverflow
Solution 10 - JavaJacky WangView Answer on Stackoverflow
Solution 11 - JavadavidxxxView Answer on Stackoverflow
Solution 12 - JavajavaseView Answer on Stackoverflow
Solution 13 - JavaucMediaView Answer on Stackoverflow
Solution 14 - JavaJavaView Answer on Stackoverflow