Подтвердить что ты не робот

Определить список фиксированного размера в Java

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

4b9b3361

Ответ 1

Да

Библиотека 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);

Ответ 2

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

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

Ответ 3

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


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

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

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


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

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

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

Ответ 4

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

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

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

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

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

Ответ 5

Обычно альтернативой для списков фиксированного размера являются массивы 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.");
    }
}

Ответ 6

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

Ответ 7

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

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

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 ...

Ответ 8

Вы можете определить обобщенную функцию следующим образом.

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

И

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

Ответ 9

Если вы хотите использовать 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.

Ответ 10

Публичные подклассы 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), но вам следует предпочесть композицию этому, поскольку она позволяет не связывать ваш класс с деталями реализации этой реализации, а также обеспечивает гибкость в реализации декорированных/составных.

С классами Guava Forwarding вы можете сделать:

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); 
//...

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