Публичные подклассы java.util.List
JDK не предоставляют функцию фиксированного размера, которая не входит в спецификацию List
.
Вы можете найти его только в Queue
подклассах (например, ArrayBlockingQueue
, ограниченная очередь блокировки, поддерживаемая, например, массивом), которые отвечают очень специфическим требованиям.
В Java с типом List
вы можете реализовать его в соответствии с двумя сценариями:
1) Фиксированный размер списка всегда является как фактическим, так и максимальным размером.
Звучит как определение массива. Так что Arrays.asList()
, который возвращает список фиксированного размера с заданным массивом, - это то, что вы ищете. Как и в случае с массивом, вы не можете ни увеличивать, ни уменьшать его размер, а только изменять его содержимое. Поэтому операции добавления и удаления не поддерживаются.
Например:
Foo[] foosInput= ...;
List<Foo> foos = Arrays.asList(foosInput);
foos.add(new Foo()); // throws an Exception
foos.remove(new Foo()); // throws an Exception
Он также работает с коллекцией в качестве входных данных, а сначала мы конвертируем ее в массив:
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) Содержание списка неизвестно сразу после его создания. Таким образом, под фиксированным размером вы подразумеваете его максимальный размер.
Вы можете использовать наследование (extends ArrayList
), но вам следует отдавать предпочтение композиции, а не тому, что это позволяет вам не связывать свой класс с деталями реализации этой реализации, а также обеспечивает гибкость в реализации декорированных / составных.
С классами перенаправления гуавы вы можете сделать:
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");
}
}
}
И используйте это:
List<String> fixedSizeList = new FixedSizeList<>(new ArrayList<>(), 3);
fixedSizeList.addAll(Arrays.asList("1", "2", "3"));
fixedSizeList.add("4"); // throws an Exception
Обратите внимание, что с композицией вы можете использовать ее с любой реализацией List
:
List<String> fixedSizeList = new FixedSizeList<>(new LinkedList<>(), 3);
//...
Что невозможно при наследовании.