javaarrayslistarraylistimplements

How to define and implement a fixed size "List" in Java?


I want to create an fixed size list in java, according to my searchings & readings from the internet i couldn't find that feature in java, However i want to create a fixed size list with 100 elements, when i want to add a new item it should remove 100th element, then adjust the index like this (99th element becomes the 100th element now(Indexes only)) and then my new element should add to the first index.

How to do such a thing in java?


Solution

  • You can have your collection class implement a List and have it delegate to an internal Deque.

    Here is the add method:

    // Note: This is the only important method to implement
    // The rest of the methods delegate to the deque field
    @Override
    public boolean add(T item) {
        // The first item falls off the deque if it's full
        if (deque.size() == maxSize) {
            deque.removeFirst(); // Remove the oldest element
        }
        return deque.add(item); // Add the new element to the end
    }
    

    Complete example

    Here are two classes; the FixedSizeDequeRunner which contains a main entry-point, and the FixedSizeDeque collection class.

    package org.example.collections;
    
    import java.util.Arrays;
    import java.util.List;
    
    public class FixedSizeDequeRunner {
        public static void main(String[] args) {
            List<String> fixedDeque = new FixedSizeDeque<>(10);
    
            for (int i = 0; i < 15; i++) {
                fixedDeque.add("Item " + i);
            }
    
            int i = 0;
            for (String item : fixedDeque) {
                System.out.printf("Index %d: %s%n", i++, item);
            }
    
            System.out.printf("Fixed Size Deque: %s%n", fixedDeque);
    
            // Convert to an array
            String[] asArray = fixedDeque.toArray(new String[0]);
            System.out.printf("Array: %s%n", Arrays.toString(asArray));
        }
    }
    

    Here is a delegation pattern that defers to a Deque:

    package org.example.collections;
    
    import java.util.ArrayDeque;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Deque;
    import java.util.Iterator;
    import java.util.List;
    import java.util.ListIterator;
    import java.util.Objects;
    
    public class FixedSizeDeque<T> implements List<T> {
        private final int maxSize;
        private final Deque<T> deque;
    
        public FixedSizeDeque(int maxSize) {
            this.maxSize = maxSize;
            this.deque = new ArrayDeque<>(maxSize);
        }
    
        // Note: This is the only important method to implement
        // The rest of the methods delegate to the deque field
        @Override
        public boolean add(T item) {
            // The first item falls off the deque if it's full
            if (deque.size() == maxSize) {
                deque.removeFirst(); // Remove the oldest element
            }
            return deque.add(item); // Add the new element to the end
        }
    
        @Override
        public boolean remove(Object o) {
            return deque.remove(o);
        }
    
        @Override
        public boolean containsAll(Collection<?> c) {
            return deque.containsAll(c);
        }
    
        @Override
        public boolean addAll(Collection<? extends T> c) {
            boolean modified = false;
            for (T item : c) {
                if (add(item)) {
                    modified = true;
                }
            }
            return modified;
        }
    
        @Override
        public boolean addAll(int index, Collection<? extends T> c) {
            if (index < 0 || index > size()) {
                throw new IndexOutOfBoundsException("Index out of bounds: " + index);
            }
            List<T> tempList = new ArrayList<>(this);
            tempList.addAll(index, c);
            if (tempList.size() > maxSize) {
                tempList = tempList.subList(tempList.size() - maxSize, tempList.size());
            }
            deque.clear();
            deque.addAll(tempList);
            return true;
        }
    
        @Override
        public boolean removeAll(Collection<?> c) {
            return deque.removeAll(c);
        }
    
        @Override
        public boolean retainAll(Collection<?> c) {
            return deque.retainAll(c);
        }
    
        @SuppressWarnings("unchecked")
        @Override
        public T get(int index) {
            if (index < 0 || index >= deque.size()) {
                throw new IndexOutOfBoundsException("Index out of bounds: " + index);
            }
            return (T) deque.toArray()[index];
        }
    
        @Override
        public T set(int index, T element) {
            if (index < 0 || index >= deque.size()) {
                throw new IndexOutOfBoundsException("Index out of bounds: " + index);
            }
            List<T> tempList = new ArrayList<>(deque);
            T oldElement = tempList.set(index, element);
            deque.clear();
            deque.addAll(tempList);
            return oldElement;
        }
    
        @Override
        public void add(int index, T element) {
            if (index < 0 || index > size()) {
                throw new IndexOutOfBoundsException("Index out of bounds: " + index);
            }
            List<T> tempList = new ArrayList<>(deque);
            tempList.add(index, element);
            if (tempList.size() > maxSize) {
                tempList = tempList.subList(tempList.size() - maxSize, tempList.size());
            }
            deque.clear();
            deque.addAll(tempList);
        }
    
        @Override
        public T remove(int index) {
            if (index < 0 || index >= deque.size()) {
                throw new IndexOutOfBoundsException("Index out of bounds: " + index);
            }
            List<T> tempList = new ArrayList<>(deque);
            T removedElement = tempList.remove(index);
            deque.clear();
            deque.addAll(tempList);
            return removedElement;
        }
    
        @Override
        public int indexOf(Object o) {
            int index = 0;
            for (T item : deque) {
                if (Objects.equals(item, o)) {
                    return index;
                }
                index++;
            }
            return -1;
        }
    
        @Override
        public int lastIndexOf(Object o) {
            int index = deque.size() - 1;
            ListIterator<T> iterator = new ArrayList<>(deque).listIterator(deque.size());
            while (iterator.hasPrevious()) {
                if (Objects.equals(iterator.previous(), o)) {
                    return index;
                }
                index--;
            }
            return -1;
        }
    
        @Override
        public ListIterator<T> listIterator() {
            return new ArrayList<>(deque).listIterator();
        }
    
        @Override
        public ListIterator<T> listIterator(int index) {
            if (index < 0 || index > size()) {
                throw new IndexOutOfBoundsException("Index out of bounds: " + index);
            }
            return new ArrayList<>(deque).listIterator(index);
        }
    
        @Override
        public List<T> subList(int fromIndex, int toIndex) {
            if (fromIndex < 0 || toIndex > size() || fromIndex > toIndex) {
                throw new IndexOutOfBoundsException("Index out of bounds: " + fromIndex + " to " + toIndex);
            }
            return new ArrayList<>(deque).subList(fromIndex, toIndex);
        }
    
        @Override
        public int size() {
            return deque.size();
        }
    
        @Override
        public boolean isEmpty() {
            return deque.isEmpty();
        }
    
        @Override
        public boolean contains(Object o) {
            return deque.contains(o);
        }
    
        @Override
        public Iterator<T> iterator() {
            return deque.iterator();
        }
    
        @Override
        public Object[] toArray() {
            return deque.toArray();
        }
    
        @Override
        public <T1> T1[] toArray(T1[] a) {
            return deque.toArray(a);
        }
    
        @Override
        public void clear() {
            deque.clear();
        }
    
        @Override
        public String toString() {
            return deque.toString();
        }
    }