Определить список фиксированного размера в Java - PullRequest
37 голосов
/ 06 марта 2011

Можно ли определить список с фиксированным размером, равным 100? Если нет, то почему это не доступно в Java?

Ответы [ 9 ]

34 голосов
/ 06 марта 2011

Это следует делать, если память служит:

List<MyType> fixed = Arrays.asList(new MyType[100]);
27 голосов
/ 06 марта 2011

Либо ваш вопрос неверен, либо у вас неверная ментальная модель того, что такое Java List.


Список Java - это набор объектов ... элементов списка,Размер списка - это количество элементов в этом списке.Если вы хотите, чтобы этот размер был фиксированным, это означает, что вы не можете ни добавлять, ни удалять элементы, потому что добавление или удаление элементов нарушит ваше ограничение «фиксированный размер».

Самый простой способ реализовать «фиксированный размер»list (если это действительно то, что вам нужно!) - поместить элементы в массив, а затем Arrays.asList(array), чтобы создать упаковщик списка.Обертка позволит вам выполнять такие операции, как get и set, но операции add и remove будут вызывать исключения.

И если вы хотите создать оболочку фиксированного размера длясуществующий список, то вы можете использовать класс Apache * FixedSizeList.Но обратите внимание, что эта оболочка не может остановить что-то еще, изменяя размер исходного списка, и если это произойдет, упакованный список, вероятно, будет отражать эти изменения.(IMO, javadoc для FixedSizeList ужасен. Он не пытается документировать, как ведет себя класс, когда изменен свернутый список. Вам нужно будет прочитать исходный код ... и надеяться, что они не изменят поведениекогда вы не обращаете внимания.)


С другой стороны, если вам действительно нужен тип списка с фиксированным лимитом (или лимитами) на его размер, то вам нужно будет создать свой собственныйСписок классов для реализации этого.Например, вы можете создать класс-оболочку, который реализует соответствующие проверки в различных операциях add / addAll и remove / removeAll / retainAll.(И в методах итератора remove, если они поддерживаются.)

Так почему же платформа Java Collections не реализует их?Вот почему я так думаю:

  1. Варианты использования, в которых это необходимо, редки.
  2. Варианты использования, где это необходимо, существуют разные требования к тому, что делать при выполнении операциипытается выйти за пределы;например, выбросить исключение, игнорировать операцию, отбросить какой-либо другой элемент, чтобы освободить место.
  3. Реализация списка с ограничениями может быть проблематичной для вспомогательных методов;например, Collections.sort.
17 голосов
/ 11 мая 2011

Да

Библиотека Commons предоставляет встроенный FixedSizeList, который не поддерживает методы add, remove и clear (но метод set разрешен, потому что он не изменяет размер List). Другими словами, если вы попытаетесь вызвать один из этих методов, ваш список все равно сохранит тот же размер.

Чтобы создать список с фиксированным размером, просто позвоните

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

Вы можете использовать unmodifiableList, если вы хотите неизменяемый просмотр указанного списка, или доступ только для чтения к внутренним спискам .

List<YourType> unmodifiable = java.util.Collections.unmodifiableList(internalList);
13 голосов
/ 06 марта 2011

Да. Вы можете передать массив Java в Arrays.asList (Object []) .

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

Вы не можете вставить новые строки в fixedSizeList (он уже содержит 100 элементов). Вы можете установить его значения только так:

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

Таким образом, у вас есть список фиксированного размера. Эта вещь функционирует как массив, и я не могу придумать вескую причину для ее использования. Мне бы хотелось услышать, почему вы хотите, чтобы ваша коллекция фиксированного размера была списком, а не просто использовала массив.

8 голосов
/ 06 марта 2011

Обычно альтернативой для фиксированного размера списков являются массивы Java.Списки по умолчанию разрешено увеличивать / уменьшать в Java.Однако это не означает, что у вас не может быть списка фиксированного размера.Вам нужно будет поработать и создать собственную реализацию.

Вы можете расширить ArrayList с помощью пользовательских реализаций методов очистки, добавления и удаления.

например

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.");
    }
}
3 голосов
/ 06 марта 2011

Создайте массив размером 100. Если вам нужен интерфейс List, тогда вызовите Arrays.asList для него. Он вернет список фиксированного размера, поддерживаемый массивом.

2 голосов
/ 06 марта 2011

Если вам нужна гибкость, создайте класс, который следит за размером списка.

Вот простой пример. Вам необходимо переопределить все методы, которые изменяют состояние списка.

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 ...
0 голосов
/ 30 июня 2019

Публичные подклассы 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); 
//...

Что невозможно при наследовании.

0 голосов
/ 13 января 2018

Если вы хотите использовать ArrayList или LinkedList , похоже, что ответ отрицательный. Хотя в java есть некоторые классы, для которых можно установить фиксированный размер, например PriorityQueue , ArrayList и LinkedList не могут этого сделать, поскольку для этих двух не существует конструктора, определяющего емкость.

Если вы хотите придерживаться ArrayList / LinkedList, одно простое решение - каждый раз проверять размер вручную.

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

LinkedList лучше, чем ArrayList в этой ситуации. Предположим, что нужно добавить много значений, но размер списка довольно большой, будет много операций удаления. Причина в том, что стоимость удаления из ArrayList составляет O (N), но только O (1) для LinkedList.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...