Konwersja tablicy obiektów na tablicę ich typów pierwotnych

80

Jeśli masz tablicę obiektów Java, które mają typ pierwotny (na przykład Byte, Integer, Char itp.). Czy istnieje zgrabny sposób na przekształcenie go w tablicę typu pierwotnego? W szczególności można to zrobić bez konieczności tworzenia nowej tablicy i przeglądania zawartości w pętli.

Na przykład dane

Integer[] array

jaki jest najładniejszy sposób przekształcenia tego w

int[] intArray

Niestety jest to coś, co musimy robić dość często, gdy łączymy się między Hibernate a niektórymi bibliotekami stron trzecich, nad którymi nie mamy kontroli. Wygląda na to, że byłaby to dość powszechna operacja, więc byłbym zaskoczony, gdyby nie było skrótu.

Dzięki za pomoc!

Il-Bhima
źródło

Odpowiedzi:

40

Niestety na platformie Java nie ma nic, co to robi. Przy okazji, musisz również jawnie obsługiwać nullelementy w Integer[]tablicy (czego intzamierzasz użyć do tego?).

Zach Scrivena
źródło
6
Dobra uwaga na temat wartości zerowych. Dla moich celów zaakceptowałbym wyrzucenie wyjątku, jeśli jeden z wpisów ma wartość null, w taki sam sposób, w jaki NullPointerException jest generowany podczas rozpakowywania obiektu.
Il-Bhima,
2
Ta odpowiedź nie jest już dokładna w przypadku języka Java 8, zobacz odpowiedź Alexa .
robinst
92

Po raz kolejny Apache Commons Lang jest twoim przyjacielem. Zapewniają ArrayUtils.toPrimitive (), który robi dokładnie to, czego potrzebujesz. Możesz określić, jak chcesz obsługiwać wartości null.

Guillaume
źródło
70

W przypadku strumieni wprowadzonych w Javie 8 można to zrobić:

int[] intArray = Arrays.stream(array).mapToInt(Integer::intValue).toArray();

Jednakże, istnieje obecnie tylko dla prymitywnych strumienie int, longi double. Jeśli chcesz przekonwertować na inny typ pierwotny, taki jak bytenajkrótszy sposób bez zewnętrznej biblioteki, to:

byte[] byteArray = new byte[array.length];
for(int i = 0; i < array.length; i++) byteArray[i] = array[i];

Jeśli chcesz, pętlę for można zastąpić strumieniem:

IntStream.range(0, array.length).forEach(i -> byteArray[i] = array[i]);

Wszystkie te rzucą, NullPointerExceptionjeśli którykolwiek z twoich elementów null.

Alex - GlassEditor.com
źródło
2
Zamiast tego Integer::intValuemożesz również użyć i -> i(który używa rozpakowywania).
robinst
1
@robinst A rozpakowywanie jest wołaniem kompilatora Integer::intValue, więc po co tworzyć nową lambdę, skoro metoda jest łatwo dostępna?
Andreas
@Andreas Wystarczy wymienić inną opcję, którą wybierzesz, jest kwestią stylu kodu / osobistych preferencji. Również oznaczyłem (używając JMH) mikroznakowanie obu podejść i mają one taką samą wydajność.
robinst
Użycie pierwszego opublikowanego fragmentu kodu dawało mi błąd „Nie można użyć metody statycznej w kontekście statycznym”, więc zamiast tego zrobiłem: int[] ints = Arrays.stream(objects).mapToInt(i -> Integer.parseInt(i.toString())).toArray(); Mam nadzieję, że jest to pomocne dla każdego, kto ma ten sam problem. A jeśli ktoś zna lepszy sposób, daj mi znać.
Kartik Chugh,
To powinna być obecnie akceptowana odpowiedź. Dzięki Alex.
Per Lundberg
27

Korzystanie z guawy :

int[] intArray = Ints.toArray(Arrays.asList(array));

Dokumentacja:

Paul Bellora
źródło
3

W szczególności można to zrobić bez konieczności tworzenia nowej tablicy i przeglądania zawartości w pętli.

Nie możesz przekonwertować tablicy typu Integer na int (tj. Nie możesz zmienić typu elementów tablicy) w Javie. Więc albo musisz utworzyć nową tablicę int [] i skopiować do niej wartość obiektów Integer, albo możesz użyć adaptera:

class IntAdapter {
    private Integer[] array;
    public IntAdapter (Integer[] array) { this.array = array; }
    public int get (int index) { return array[index].intValue(); }
}

Może to uczynić twój kod bardziej czytelnym, a obiekt IntAdapter będzie zużywał tylko kilka bajtów pamięci. Dużą zaletą adaptera jest to, że poradzisz sobie tutaj ze specjalnymi przypadkami:

class IntAdapter {
    private Integer[] array;
    public int nullValue = 0;
    public IntAdapter (Integer[] array) { this.array = array; }
    public int get (int index) { 
        return array[index] == null ? nullValue : array[index].intValue();
    }
}

Innym rozwiązaniem jest użycie Commons Primitives, który zawiera wiele predefiniowanych adapterów. W twoim przypadku spójrz na ListIntList .

Aaron Digulla
źródło
2

Lub po prostu zrób to w łatwy sposób, jeśli chcesz to zrobić tylko raz. Ale nie rozmawiałeś o Integer! = Null case.

    //array is the Integer array
    int[] array2 = new int[array.length];
    int i=0;
    for (Integer integer : array) {
        array2[i] = integer.intValue();
        i++;
    }
Jens Jansson
źródło
1

korzystanie z dolara jest proste, jak:

Integer[] array = ...;
int[] primitiveArray = $(array).toIntArray();
dfa
źródło
6
To nie wydaje się być Java, przynajmniej nie Java 1.6 lub 1.7.
Lordalcol
2
@LorDalCol Dollar jest właściwie biblioteką Java
Jaroslav Záruba
1
Możliwe jest nazwanie metody Java $! Nie wydaje mi się jednak, żeby to było zachęcane…
Ole VV