webentwicklung-frage-antwort-db.com.de

Konvertieren Sie ein Array von primitiven Longs in eine Liste von Longs

Dies mag eine leichte Frage sein, aber mein erster Versuch schlug überraschenderweise völlig fehl. Ich wollte eine Reihe von primitiven Sehnsüchten nehmen und daraus eine Liste machen, was ich so versuchte:

long[] input = someAPI.getSomeLongs();
List<Long> inputAsList = Arrays.asList(input); //Total failure to even compile!

Was ist der richtige Weg, um dies zu tun?

131

Ich fand es praktisch, Apache-Commons zu verwenden. Lang ArrayUtils ( JavaDoc , Maven-Abhängigkeit )

import org.Apache.commons.lang3.ArrayUtils;
...
long[] input = someAPI.getSomeLongs();
Long[] inputBoxed = ArrayUtils.toObject(input);
List<Long> inputAsList = Arrays.asList(inputBoxed);

es hat auch die umgekehrte API

long[] backToPrimitive = ArrayUtils.toPrimitive(objectArray);

BEARBEITEN: wurde aktualisiert, um eine vollständige Konvertierung in eine Liste bereitzustellen, wie durch Kommentare und andere Korrekturen vorgeschlagen.

107
Eran Medan

Seit Java 8 können Sie dafür jetzt Streams verwenden:

long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
99
marcinj
import Java.util.Arrays;
import org.Apache.commons.lang.ArrayUtils;

List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));
37
Marco Pelegrini

hallidave und jpalecek haben die richtige Idee - über ein Array iterieren - aber sie nutzen eine Funktion von ArrayList nicht: since Die Größe der Liste ist bekannt . In diesem Fall sollten Sie diese beim Erstellen von ArrayList angeben.

List<Long> list = new ArrayList<Long>(input.length);
for (long n : input)
  list.add(n);

Auf diese Weise werden keine unnötigen Arrays erstellt, die nur vom ArrayList verworfen werden, weil sie zu kurz sind, und es werden keine leeren "Slots" verschwendet, weil ArrayList den Platzbedarf überschätzt hat. Wenn Sie der Liste weiterhin Elemente hinzufügen, wird natürlich ein neues Sicherungsarray benötigt.

34
erickson

Ein bisschen ausführlicher, aber das funktioniert:

    List<Long> list = new ArrayList<Long>();
    for (long value : input) {
        list.add(value);
    }

In Ihrem Beispiel sieht es so aus, als würde Arrays.asList () die Eingabe als Liste von langen [] Arrays interpretieren, anstatt als Liste von Longs. Sicher ein bisschen überraschend. Autoboxen funktioniert in diesem Fall einfach nicht so, wie Sie es möchten.

19
hallidave

Als weitere Möglichkeit bietet die Guava-Bibliothek dies als Longs.asList() mit ähnlichen Dienstprogrammklassen für die anderen primitiven Typen.

import com.google.common.primitives.Longs;

long[] input = someAPI.getSomeLongs();
List<Long> output = Longs.asList(input);
17
Trevor Robinson

Nein, es gibt keine automatische Konvertierung von einem Array des primitiven Typs in ein Array der darin enthaltenen Referenztypen. Sie können nur tun

long[] input = someAPI.getSomeLongs();
List<Long> lst = new ArrayList<Long>();

for(long l : input) lst.add(l);
7
jpalecek

Ich schreibe eine kleine Bibliothek für diese Probleme:

long[] input = someAPI.getSomeLongs();
List<Long> = $(input).toList();

Falls es Ihnen wichtig ist, überprüfen Sie es hier .

6
dfa

Ein anderer Weg mit Java 8.

long[] input = someAPI.getSomeLongs();
LongStream.of(input).boxed().collect(Collectors.toList()));
6
ravenskater

Die Frage lautete, wie ein Array in eine Liste umgewandelt werden kann. Die meisten bisherigen Antworten zeigten, wie eine new - Liste mit demselben Inhalt wie das Array erstellt oder auf Bibliotheken von Drittanbietern verwiesen werden kann. Es gibt jedoch einfache, integrierte Optionen für diese Art der Konvertierung. Einige von ihnen wurden bereits in anderen Antworten skizziert (z. B. diese ). Ich möchte hier jedoch auf bestimmte Freiheitsgrade für die Implementierung hinweisen und diese ausarbeiten und die potenziellen Vor- und Nachteile sowie Vorbehalte aufzeigen.

Es sind mindestens zwei wichtige Unterscheidungen zu treffen:

  • Ob die resultierende Liste eine Ansicht des Arrays sein soll oder ob es sich um eine neue Liste handeln soll
  • Ob die resultierende Liste änderbar sein soll oder nicht

Die Optionen werden hier kurz zusammengefasst. Ein vollständiges Beispielprogramm finden Sie am Ende dieser Antwort.


Erstellen einer neuen Liste versus Erstellen einer Ansicht auf dem Array

Wenn das Ergebnis eine neue Liste sein soll, kann einer der Ansätze aus den anderen Antworten verwendet werden:

List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());

Dabei sollte man jedoch die Nachteile berücksichtigen: Ein Array mit 1000000 long Werten belegt ungefähr 8 Megabyte Speicher. Die neue Liste wird also ungefähr 8 Megabyte belegen. Und natürlich muss beim Erstellen dieser Liste das gesamte Array durchlaufen werden. In vielen Fällen ist das Erstellen einer neuen Liste einfach nicht erforderlich. Stattdessen reicht es aus, eine Ansicht auf dem Array zu erstellen:

// This occupies ca. 8 MB
long array[] = { /* 1 million elements */ }

// Properly implemented, this list will only occupy a few bytes,
// and the array does NOT have to be traversed, meaning that this
// operation has nearly ZERO memory- and processing overhead:
List<Long> list = asList(array);

(Eine Implementierung der toList -Methode finden Sie im Beispiel unten.)

Die Konsequenz eines view im Array ist, dass Änderungen im Array in der Liste sichtbar sind:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

System.out.println(list.get(1)); // This will print 34

// Modify the array contents:
array[1] = 12345;

System.out.println(list.get(1)); // This will now print 12345!

Glücklicherweise ist das Erstellen einer Kopie (dh einer neuen Liste, die nicht von Änderungen im Array betroffen ist) aus der Ansicht trivial:

List<Long> copy = new ArrayList<Long>(asList(array));

Dies ist eine echte Kopie, die dem entspricht, was mit der oben gezeigten Stream-basierten Lösung erreicht wird.


Erstellen einer änderbaren Ansicht oder einer nicht änderbaren Ansicht

In vielen Fällen ist es ausreichend, wenn die Liste schreibgeschützt ist. Der Inhalt der resultierenden Liste wird häufig nicht geändert, sondern nur an die nachgeschaltete Verarbeitung übergeben, die nur die Liste liest.

Das Zulassen von Änderungen an der Liste wirft einige Fragen auf:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

list.set(2, 34567);           // Should this be possible?
System.out.println(array[2]); // Should this print 34567?
list.set(3, null);            // What should happen here?
list.add(99999);              // Should this be possible?

Es ist möglich, eine Listenansicht für das Array zu erstellen, die änderbar ist. Dies bedeutet, dass Änderungen in der Liste, wie das Festlegen eines neuen Werts an einem bestimmten Index, im Array sichtbar werden.

Es ist jedoch nicht möglich, eine Listenansicht zu erstellen, die strukturell änderbar ist. Dies bedeutet, dass keine Operationen ausgeführt werden können, die die Größe der Liste betreffen. Dies liegt einfach daran, dass die Größe des zugrunde liegenden Arrays array nicht geändert werden kann.


Das Folgende ist ein MCVE , das die verschiedenen Implementierungsoptionen und die möglichen Verwendungsmöglichkeiten der resultierenden Listen zeigt:

import Java.util.AbstractList;
import Java.util.ArrayList;
import Java.util.Arrays;
import Java.util.List;
import Java.util.Objects;

public class PrimitiveArraysAsLists
{
    public static void main(String[] args)
    {
        long array[] = { 12, 34, 56, 78 };

        // Create VIEWS on the given array
        List<Long> list = asList(array);
        List<Long> unmodifiableList = asUnmodifiableList(array);

        // If a NEW list is desired (and not a VIEW on the array), this
        // can be created as well:
        List<Long> copy = new ArrayList<Long>(asList(array));

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value in the array. The changes will be visible
        // in the list and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 1 of the array...");
        array[1] = 34567;

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value of the list. The changes will be visible
        // in the array and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 2 of the list...");
        list.set(2, 56789L);

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        


        // Certain operations are not supported:
        try
        {
            // Throws an UnsupportedOperationException: This list is 
            // unmodifiable, because the "set" method is not implemented
            unmodifiableList.set(2, 23456L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }

        try
        {
            // Throws an UnsupportedOperationException: The size of the
            // backing array cannot be changed
            list.add(90L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }


        try
        {
            // Throws a NullPointerException: The value 'null' cannot be  
            // converted to a primitive 'long' value for the underlying array
            list.set(2, null);
        }
        catch (NullPointerException e)
        {
            System.out.println("Expected: " + e);
        }

    }

    /**
     * Returns an unmodifiable view on the given array, as a list.
     * Changes in the given array will be visible in the returned
     * list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asUnmodifiableList(long array[])
    {
        Objects.requireNonNull(array);
        return new AbstractList<Long>()
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
    }

    /**
     * Returns a view on the given array, as a list. Changes in the given 
     * array will be visible in the returned list, and vice versa. The
     * list does not allow for <i>structural modifications</i>, meaning
     * that it is not possible to change the size of the list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asList(long array[])
    {
        Objects.requireNonNull(array);
        return new AbstractList<Long>()
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public Long set(int index, Long element)
            {
                long old = array[index];
                array[index] = element;
                return old;
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
    }

}

Die Ausgabe des Beispiels wird hier gezeigt:

array           : [12, 34, 56, 78]
list            : [12, 34, 56, 78]
unmodifiableList: [12, 34, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 1 of the array...
array           : [12, 34567, 56, 78]
list            : [12, 34567, 56, 78]
unmodifiableList: [12, 34567, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 2 of the list...
array           : [12, 34567, 56789, 78]
list            : [12, 34567, 56789, 78]
unmodifiableList: [12, 34567, 56789, 78]
copy            : [12, 34, 56, 78]
Expected: Java.lang.UnsupportedOperationException
Expected: Java.lang.UnsupportedOperationException
Expected: Java.lang.NullPointerException
5
Marco13

Ein weiteres Weg mit Java 8.

final long[] a = new long[]{1L, 2L};
final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());
3
Jin Kwon

Wenn wir die Antworten von Pavel und Tom kombinieren, bekommen wir das

   @SuppressWarnings("unchecked")
    public static <T> List<T> asList(final Object array) {
        if (!array.getClass().isArray())
            throw new IllegalArgumentException("Not an array");
        return new AbstractList<T>() {
            @Override
            public T get(int index) {
                return (T) Array.get(array, index);
            }

            @Override
            public int size() {
                return Array.getLength(array);
            }
        };
    }
3
Duncan McGregor

Ich weiß, dass diese Frage alt genug ist, aber ... Sie können auch Ihre eigene Konvertierungsmethode schreiben:

@SuppressWarnings("unchecked")
public static <T> List<T> toList(Object... items) {

    List<T> list = new ArrayList<T>();

    if (items.length == 1 && items[0].getClass().isArray()) {
        int length = Array.getLength(items[0]);
        for (int i = 0; i < length; i++) {
            Object element = Array.get(items[0], i);
            T item = (T)element;
            list.add(item);
        }
    } else {
        for (Object i : items) {
            T item = (T)i;
            list.add(item);
        }
    }

    return list;
}

Nachdem Sie es mithilfe des statischen Imports eingefügt haben, können folgende Verwendungen auftreten:

    long[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    List<Long> list = toList(array);

oder

    List<Long> list = toList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l);
2
Pavel Netesa

Wenn Sie eine ähnliche Semantik wünschen wie Arrays.asList dann müssen Sie die Kundenimplementierung von List (wahrscheinlich durch AbstractList) schreiben (oder von einer anderen Person verwenden). Sie sollte ungefähr dieselbe Implementierung haben wie Arrays.asList, nur Box- und Unbox-Werte.

Sie können transmorph verwenden:

Transmorph transmorph = new Transmorph(new DefaultConverters());
List<Long> = transmorph.convert(new long[] {1,2,3,4}, new TypeReference<List<Long>>() {});

Dies funktioniert auch, wenn die Quelle beispielsweise ein Array von Ints ist.

2
cchabanois

Während es möglich ist, eine neue Liste zu erstellen und alle Werte hinzuzufügen (über for loop oder streams), habe ich an wirklich großen Arrays gearbeitet und eine schlechte Leistung erzielt. Aus diesem Grund habe ich meine eigene einfach zu verwendende Array-Wrapper-Klasse erstellt.

Beispiel:

long[] arr = new long[] {1,2,3};
PrimativeList<Long> list = PrimativeList.create(arr); // detects long[] and returns PrimativeList<Long>

System.out.println(list.get(1)); // prints: 2
list.set(2, 15);
System.out.println(arr[2]);  // prints: 15

Laden Sie es hier herunter: https://github.com/Sf298/Sauds-Toolbox/blob/master/src/main/Java/PrimitiveArrayWrapper/PrimitiveList.Java

HINWEIS: Ich habe es noch nicht vollständig getestet. Lassen Sie mich wissen, wenn Sie Fehler oder Probleme feststellen.

1
sf298

Sie können dafür LongStream verwenden

List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
                             .collect(Collectors.toList());
0