it-swarm.com.de

Definieren Sie eine Liste mit fester Größe in Java

Kann eine Liste mit einer festen Größe von 100 definiert werden? Wenn nicht, warum ist dies nicht in Java verfügbar?

37
fastcodejava

Ja,

Commons-Bibliothek enthält eine integrierte FixedSizeList , die die Methoden add, remove und clear nicht unterstützt (die set-Methode ist jedoch zulässig, da sie die Größe der List nicht ändert). Wenn Sie also versuchen, eine dieser Methoden aufzurufen, behält Ihre Liste dieselbe Größe.

Um Ihre Liste mit fester Größe zu erstellen, rufen Sie einfach an

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

Sie können unmodifiableList verwenden, wenn Sie eine unveränderbare Ansicht der angegebenen Liste wünschen, oder read-only-Zugriff auf interne Listen.

List<YourType> unmodifiable = Java.util.Collections.unmodifiableList(internalList);
17
Arthur Ronald

Dies sollte es tun, wenn der Speicher dient:

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

Entweder ist Ihre Frage falsch angegeben oder Sie haben ein falsches Denkmodell, was Java List ist.


Eine Java-Liste ist eine Sammlung von Objekten ... die Elemente einer Liste. Die Größe der Liste ist die Anzahl der Elemente in dieser Liste. Wenn Sie möchten, dass diese Größe festgelegt wird, können Sie keine Elemente hinzufügen oder entfernen, da das Hinzufügen oder Entfernen von Elementen Ihre Einschränkung "Feste Größe" verletzen würde.

Die einfachste Möglichkeit, eine "feste Größe" -Liste zu implementieren (wenn Sie das wirklich wollen!), Besteht darin, die Elemente in ein Array zu stellen und dann Arrays.asList(array), um den Listen-Wrapper zu erstellen. Mit dem Wrapper können Sie Operationen wie get und set ausführen, aber die Operationen add und remove lösen Ausnahmen aus.

Wenn Sie einen Wrapper mit fester Größe für eine vorhandene Liste erstellen möchten, können Sie die Klasse Apache FixedSizeList verwenden. Beachten Sie jedoch, dass dieser Wrapper nichts anderes daran hindern kann, die Größe der ursprünglichen Liste zu ändern. In diesem Fall spiegelt die umwickelte Liste vermutlich diese Änderungen wider. (IMO, der Javadoc für FixedSizeList ist wehmütig. Es macht keinen Versuch zu dokumentieren, wie sich die Klasse verhält, wenn die umwickelte Liste geändert wird. Sie müssen den Quellcode lesen ... und hoffen, dass sie das Verhalten nicht ändern, wenn Sie dies tun nicht aufpassen.)


Auf der anderen Seite, wenn Sie wirklich einen Listentyp mit einem festen Limit (oder Limits) für seine Größe wünschen, müssen Sie eine eigene List-Klasse erstellen, um dies zu implementieren. Sie können beispielsweise eine Wrapper-Klasse erstellen, die die entsprechenden Prüfungen in den verschiedenen add/addAll- und remove/removeAll/retainAll-Operationen implementiert. (Und in den Iterator remove-Methoden, falls diese unterstützt werden.)

Warum implementiert das Java Collections-Framework diese nicht? Ich denke so:

  1. Anwendungsfälle, die dies benötigen, sind selten.
  2. In den Anwendungsfällen, in denen dies erforderlich ist, gibt es unterschiedliche Anforderungen, was zu tun ist, wenn eine Operation versucht, die Grenzwerte zu überschreiten. z.B. Ausnahme auslösen, Vorgang ignorieren, andere Elemente verwerfen, um Platz zu schaffen.
  3. Eine Listenimplementierung mit Grenzwerten könnte für Hilfsmethoden problematisch sein. z.B. Collections.sort.
27
Stephen C

Ja. Sie können ein Java-Array an Arrays.asList (Object []) übergeben.

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

Sie können keine neuen Zeichenfolgen in die fixedSizeList einfügen (diese hat bereits 100 Elemente). Sie können die Werte nur so einstellen:

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

Auf diese Weise haben Sie eine feste Größenliste. Das Ding funktioniert wie ein Array und mir fällt kein guter Grund ein, es zu benutzen. Ich würde gerne hören, warum Ihre Sammlung mit fester Größe eine Liste sein soll, anstatt nur ein Array zu verwenden.

12
snakile

Eine Alternative für Listen mit fester Größe sind normalerweise Java-Arrays. Listen können in Java standardmäßig vergrößert/verkleinert werden. Das bedeutet jedoch nicht, dass Sie keine Liste mit fester Größe haben können. Sie müssen etwas arbeiten und eine benutzerdefinierte Implementierung erstellen.

Sie können eine ArrayList mit benutzerdefinierten Implementierungen der clear-, add- und remove-Methoden erweitern.

z.B.

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.");
    }
}
8
shams

Erstellen Sie ein Array der Größe 100. Wenn Sie die List-Schnittstelle benötigen, rufen Sie Arrays.asList auf. Es wird eine Liste fester Größe zurückgegeben, die vom Array gesichert wird.

Wenn Sie etwas Flexibilität wünschen, erstellen Sie eine Klasse, die die Größe der Liste überwacht.

Hier ist ein einfaches Beispiel. Sie müssten alle Methoden überschreiben, die den Status der Liste ändern.

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

Sie können generische Funktionen wie diese definieren.

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

Und

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

Die öffentlichen Java.util.List - Unterklassen des JDK bieten keine Funktion mit fester Größe, die nicht Teil der List -Spezifikation ist.
Sie können es nur in Queue Unterklassen finden (z. B. ArrayBlockingQueue, eine begrenzte Blockierungswarteschlange, die von einem Array unterstützt wird), die sehr spezielle Anforderungen erfüllen.

In Java können Sie es mit einem List -Typ in zwei Szenarien implementieren:

1) Die feste Listengröße ist immer sowohl die tatsächliche als auch die maximale Größe.

Es klingt wie eine Array-Definition. Also Arrays.asList(), das eine Liste mit fester Größe zurückgibt, die von dem angegebenen Array unterstützt wird, ist das, wonach Sie suchen. Und wie bei einem Array können Sie die Größe weder erhöhen noch verringern, sondern nur den Inhalt ändern. Das Hinzufügen und Entfernen von Vorgängen wird daher nicht unterstützt.

Beispielsweise :

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

Es funktioniert auch mit einer Sammlung als Eingabe, während wir sie zuerst in ein Array konvertieren:

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) Der Listeninhalt ist nicht bekannt, sobald er erstellt wurde. Also meinst du mit feste Größe Liste seine maximale Größe.

Sie könnten die Vererbung (extends ArrayList) Verwenden, sollten jedoch die Komposition der Komposition vorziehen, da Sie dadurch Ihre Klasse nicht mit den Implementierungsdetails dieser Implementierung koppeln können und auch Flexibilität hinsichtlich der Implementierung der dekorierten/komponierten Klasse haben.

Mit Guava Forwarding Klassen können Sie Folgendes tun:

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");
    }
  }

}

Und benutze es:

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

Beachten Sie, dass Sie die Komposition mit jeder List -Implementierung verwenden können:

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

Was bei Vererbung nicht möglich ist.

0
davidxxx

Wenn Sie ArrayList oder LinkedList verwenden möchten, scheint die Antwort nein zu sein. Es gibt zwar einige Klassen in Java, für die Sie eine feste Größe festlegen können, z. B. PriorityQueue , ArrayList und LinkedList nicht, da es keinen Konstruktor für diese beiden gibt, um die Kapazität anzugeben.

Wenn Sie bei ArrayList/LinkedList bleiben möchten, können Sie die Größe jedes Mal manuell überprüfen.

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

LinkedList ist in dieser Situation besser als ArrayList. Angenommen, es gibt viele Werte, die hinzugefügt werden müssen, aber die Listengröße ist ziemlich klein. Es gibt viele Entfernungsvorgänge. Der Grund dafür ist, dass die Kosten für das Entfernen von ArrayList O (N) sind, für LinkedList jedoch nur O(1).

0
Jacky Wang