625 Stimmen

Set in Liste umwandeln ohne neue Liste zu erstellen

Ich verwende diesen Code zur Konvertierung einer Set a un List :

Map<String, List<String>> mainMap = new HashMap<>();

for (int i=0; i < something.size(); i++) {
  Set<String> set = getSet(...); //returns different result each time
  List<String> listOfNames = new ArrayList<>(set);
  mainMap.put(differentKeyName, listOfNames);
}

Ich möchte vermeiden, dass bei jeder Iteration der Schleife eine neue Liste erstellt wird. Ist das möglich?

23voto

beatngu13 Punkte 4876

Da es bisher noch nicht erwähnt wurde, können Sie ab Java 10 die neue copyOf Fabrikmethode:

List.copyOf(set);

Desde el Javadoc :

Gibt eine unveränderbare Liste die die Elemente der angegebenen Sammlung in der Reihenfolge ihrer Iteration enthält.

Beachten Sie, dass wird eine neue Liste erstellt ( ImmutableCollections$ListN um genau zu sein) unter der Haube von

  1. aufrufen Collection#toArray() auf die gegebene Menge und dann
  2. Diese Objekte werden in ein neues Array eingefügt.

8voto

Daniel Avery Punkte 99

Der Vollständigkeit halber...

Sagen Sie, dass Sie wirklich wollen die Behandlung der Map Werte als List s, aber Sie wollen das Kopieren der Set in eine List jedes Mal.

Zum Beispiel können Sie eine Bibliotheksfunktion aufrufen, die eine Set aber Sie übergeben Ihre Map<String, List<String>> Ergebnis an eine (schlecht konzipierte, aber nicht in Ihrer Hand liegende) Bibliotheksfunktion, die nur die Map<String, List<String>> auch wenn irgendwie weiß man dass die Operationen, die es mit dem List s sind gleichermaßen auf alle Collection (und damit jede Set ). Und aus irgendeinem Grund müssen Sie den Geschwindigkeits-/Speicher-Overhead des Kopierens jedes Sets in eine Liste vermeiden.

In diesem Super-Nischenfall hängt es von dem (vielleicht unbekannten) Verhalten ab, das die Bibliotheksfunktion von Ihrer List s, können Sie möglicherweise eine List siehe über jede Menge. Beachten Sie, dass dies inhärent unsicher ist (weil die Anforderungen der Bibliotheksfunktion von jedem List könnte sich vermutlich ändern, ohne dass Sie es merken), daher sollte eine andere Lösung bevorzugt werden. Aber hier ist, wie Sie es tun würden.

Sie würden eine Klasse erstellen, die die List Schnittstelle, nimmt eine Set im Konstruktor und weist dieses Set einem Feld zu, und verwendet dann dieses interne Set zur Umsetzung der List API (soweit dies möglich und gewünscht ist).

Beachten Sie, dass Sie einige Verhaltensweisen von Listen einfach nicht imitieren können, ohne die Elemente als List und einige Verhaltensweisen werden Sie nur teilweise imitieren können. Auch hier gilt: Dieser Kurs ist kein sicherer Ersatz für List s im Allgemeinen. Insbesondere, wenn Sie wissen, dass der Anwendungsfall indexbezogene Operationen oder MUTATING der List würde dieser Ansatz sehr schnell scheitern.

public class ListViewOfSet<U> implements List<U> {
    private final Set<U> wrappedSet;
    public ListViewOfSet(Set<U> setToWrap) { this.wrappedSet = setToWrap; }

    @Override public int size() { return this.wrappedSet.size(); }
    @Override public boolean isEmpty() { return this.wrappedSet.isEmpty(); }
    @Override public boolean contains(Object o) { return this.wrappedSet.contains(o); }
    @Override public java.util.Iterator<U> iterator() { return this.wrappedSet.iterator(); }
    @Override public Object[] toArray() { return this.wrappedSet.toArray(); }
    @Override public <T> T[] toArray(T[] ts) { return this.wrappedSet.toArray(ts); }
    @Override public boolean add(U e) { return this.wrappedSet.add(e); }
    @Override public boolean remove(Object o) { return this.wrappedSet.remove(o); }
    @Override public boolean containsAll(Collection<?> clctn) { return this.wrappedSet.containsAll(clctn); }
    @Override public boolean addAll(Collection<? extends U> clctn) { return this.wrappedSet.addAll(clctn); }
    @Override public boolean addAll(int i, Collection<? extends U> clctn) { throw new UnsupportedOperationException(); }
    @Override public boolean removeAll(Collection<?> clctn) { return this.wrappedSet.removeAll(clctn); }
    @Override public boolean retainAll(Collection<?> clctn) { return this.wrappedSet.retainAll(clctn); }
    @Override public void clear() { this.wrappedSet.clear(); }
    @Override public U get(int i) { throw new UnsupportedOperationException(); }
    @Override public U set(int i, U e) { throw new UnsupportedOperationException(); }
    @Override public void add(int i, U e) { throw new UnsupportedOperationException(); }
    @Override public U remove(int i) { throw new UnsupportedOperationException(); }
    @Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
    @Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
    @Override public ListIterator<U> listIterator() { throw new UnsupportedOperationException(); }
    @Override public ListIterator<U> listIterator(int i) { throw new UnsupportedOperationException(); }
    @Override public List<U> subList(int i, int i1) { throw new UnsupportedOperationException(); }
}

...
Set<String> set = getSet(...);
ListViewOfSet<String> listOfNames = new ListViewOfSet<>(set);
...

5voto

Jerome L Punkte 577

Ich würde es tun:

Map<String, Collection> mainMap = new HashMap<String, Collection>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); //return different result each time
  mainMap.put(differentKeyName,set);
}

5voto

Saheed Punkte 7632

Sie könnten diese eine Zeilenänderung verwenden: Arrays.asList(set.toArray(new Object[set.size()]))

Map<String, List> mainMap = new HashMap<String, List>();

for(int i=0; i<something.size(); i++){
  Set set = getSet(...); 
  mainMap.put(differentKeyName, Arrays.asList(set.toArray(new Object[set.size()])));
}

4voto

akhil_mittal Punkte 20953

Java 8 bietet die Möglichkeit, Streams zu verwenden, und Sie können eine Liste von Set<String> setString als:

List<String> stringList = setString.stream().collect(Collectors.toList());

Auch wenn die interne Implementierung derzeit eine Instanz von ArrayList :

public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }

aber das JDK garantiert dies nicht. Wie erwähnt aquí :

Es gibt keine Garantien für den Typ, die Veränderbarkeit, die Serialisierbarkeit oder die Thread-Sicherheit der zurückgegebenen Liste; wenn mehr Kontrolle über die zurückgegebene Liste erforderlich ist, verwenden Sie toCollection(Supplier).

Wenn Sie immer sicher sein wollen, können Sie eine Instanz speziell als anfordern:

List<String> stringArrayList = setString.stream()
                     .collect(Collectors.toCollection(ArrayList::new));

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X