Converting an array of objects to an array of their primitive types
Asked Answered
O

10

85

If you have an array of Java objects which have a primitive type (for example Byte, Integer, Char, etc). Is there a neat way I can convert it into an array of the primitive type? In particular can this be done without having to create a new array and loop through the contents.

So for example, given

Integer[] array

what is the neatest way to convert this into

int[] intArray

Unfortunately, this is something we have to do quite frequently when interfacing between Hibernate and some third party libraries over which we have no control. It seems this would be a quite common operation so I would be surprised if there's no shortcut.

Thanks for your help!

Omniumgatherum answered 19/2, 2009 at 8:26 Comment(0)
H
39

Unfortunately, there's nothing in the Java platform that does this. Btw, you also need to explicitly handle null elements in the Integer[] array (what int are you going to use for those?).

Hulbert answered 19/2, 2009 at 8:37 Comment(2)
Good point about the nulls. For my purposes I would have accepted an exception being thrown if one of the entries is null, the same way an NullPointerException is thrown when you unbox an object.Omniumgatherum
This answer is no longer accurate with Java 8, see Alex's answer.Momentum
S
93

Once again, Apache Commons Lang is your friend. They provide ArrayUtils.toPrimitive() which does exactly what you need. You can specify how you want to handle nulls.

Switch answered 19/2, 2009 at 9:7 Comment(0)
C
81

With streams introduced in Java 8 this can be done:

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

However, there are currently only primitive streams for int, long and double. If you need to convert to another primitive type such as byte the shortest way without an external library is this:

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

Or the for loop can be replaced with a stream if you want:

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

All of these will throw a NullPointerException if any of your elements are null.

Charkha answered 13/7, 2014 at 6:27 Comment(7)
Instead of Integer::intValue, you can also use i -> i (which uses unboxing).Momentum
@Momentum And unboxing is the compiler calling Integer::intValue for you, so why create a new lambda, when the method is readily available?Shutout
@Shutout Just listing another option, which one you choose is a question of code style/personal preference. I also microbenchmarked (using JMH) the two approaches, and they have the same performance.Momentum
Using the first code snippet posted was giving me a "Can't use non-static method in static context" error so I instead did: int[] ints = Arrays.stream(objects).mapToInt(i -> Integer.parseInt(i.toString())).toArray(); Hope this is helpful for anyone with the same issue. And if anyone knows a better way please let me know.Diacaustic
This should be the accepted answer nowadays. Thanks Alex.Walford
Arrays.setAll(unboxed, i -> boxed[i]); is a nice alternative to the for loop from my perspective.Lampkin
@BjörnZurmaar setAll only has overloads for the same primitive types as streams, so you couldn't use it for byte, but you could do Arrays.setAll(array, i -> byteArray[i] = array[i]) which will also write to the original array.Charkha
H
39

Unfortunately, there's nothing in the Java platform that does this. Btw, you also need to explicitly handle null elements in the Integer[] array (what int are you going to use for those?).

Hulbert answered 19/2, 2009 at 8:37 Comment(2)
Good point about the nulls. For my purposes I would have accepted an exception being thrown if one of the entries is null, the same way an NullPointerException is thrown when you unbox an object.Omniumgatherum
This answer is no longer accurate with Java 8, see Alex's answer.Momentum
E
27

Using Guava:

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

Documentation:

Elwaine answered 13/9, 2013 at 20:5 Comment(0)
B
3

In particular can this be done without having to create a new array and loop through the contents.

You can't convert an array of Integer to int (i.e. you can't change the type of the elements of an array) in Java. So you either must create a new int[] array and copy the value of the Integer objects into it or you can use an adapter:

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

This can make your code a little more readable and the IntAdapter object will only consume a few bytes of memory. The big advantage of an adapter is that you can handle special cases here:

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

Another solution is to use Commons Primitives which contains lots of predefined adapters. In your case, have a look at ListIntList.

Behistun answered 19/2, 2009 at 8:41 Comment(0)
I
2

Or just do it the easy way if you gonna do it only once. But you haven't talked about 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++;
    }
Infest answered 19/2, 2009 at 8:46 Comment(0)
S
0

using Dollar is simple as:

Integer[] array = ...;
int[] primitiveArray = $(array).toIntArray();
Sigma answered 1/2, 2010 at 20:17 Comment(3)
This does not appear to be Java, at least not Java 1.6 or 1.7.Bostow
@LorDalCol Dollar is actually a Java libraryKnickknack
It is possible to name a Java method $! I don’t think it’s encouraged, though…Hexosan
S
0

We can use Stream API to create primitive type arrays from their boxed object counterparts.

For Character[] array conversion to char[], using an accordingly size-allocated custom Collector, with Supplier<CharBuffer>, BiConsumer<CharBuffer, Character> accumulator, BinaryOperator<CharBuffer> combiner and Function<CharBuffer, char[]> finisher), as following will work:

Collector<Character, CharBuffer, char[]> charArrayCollector = Collector.of(
  () -> CharBuffer.allocate(95), 
  CharBuffer::put, 
  CharBuffer::put, 
  CharBuffer::array
);

It supplies the CharBuffer for the printable ASCII chars, accumulating each streamed Character into a CharBuffer instance, combining parallelized processing results from multiple CharBuffer instances in correct order and finally builds the desired char[] array from the accumulated and combined results, after all threads have finished.

First, we're creating a Character[] test array from the standard printable ASCII set, by utilizing the int values from an IntStream, by iterating the ASCII range and mapping each value into a Character Stream, after casting them to char primitives and converting those to Character objects:

Character[] asciiCharacters = IntStream.range(32, 127)
  .mapToObj(i -> Character.valueOf((char)i))
  .toArray(Character[]::new);

Now, we simply need to create a Stream of Characters from the Character array, which then can be collected into a char[] array, by the custom Collector.

char[] asciiChars = Stream.of(asciiCharacters ).collect(charArrayCollector);

This works for other Number types accordingly:

byte[] bytes = new byte[] { Byte.MIN_VALUE, -1 , 0, 1, Byte.MAX_VALUE };
Byte[] boxedBytes = IntStream.range(0, bytes.length)
  .mapToObj(i -> bytes[i])
  .toArray(Byte[]::new);
byte[] collectedBytes = Stream.of(boxedBytes).collect(
  Collector.of(
    () -> ByteBuffer.allocate(boxedBytes.length), 
    ByteBuffer::put, 
    ByteBuffer::put, 
    ByteBuffer::array
  )
);

short[] shorts = new short[] { Short.MIN_VALUE, -1, 0, 1, Short.MAX_VALUE };
Short[] boxedShorts = IntStream.range(0, shorts.length)
  .mapToObj(i -> shorts[i])
  .toArray(Short[]::new);
short[] collectedShorts = Stream.of(boxedShorts).collect(
  Collector.of(
    () -> ShortBuffer.allocate(boxedShorts .length), 
    ShortBuffer::put, 
    ShortBuffer::put, 
    ShortBuffer::array
  )
);

float[] floats = new float[] { Float.MIN_VALUE, -1.0f, 0f, 1.0f, Float.MAX_VALUE };
Float[] boxedFLoats = IntStream.range(0, floats.length)
  .mapToObj(i -> floats[i])
  .toArray(Float[]::new);
float[] collectedFloats = Stream.of(boxedFLoats).collect(
  Collector.of(
    () -> FloatBuffer.allocate(boxedFLoats.length), 
    FloatBuffer::put, 
    FloatBuffer::put, 
    FloatBuffer::array
  )
);

The primitive types, for which Stream API supports it, can be converted a bit easier:

int[] ints = new int[] { Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE };
Integer[] integers = IntStream.of(ints).boxed().toArray(Integer[]::new);
int[] collectedInts = Stream.of(integers).collect(
  Collector.of(
    () -> IntBuffer.allocate(integers.length), 
    IntBuffer::put, 
    IntBuffer::put, 
    IntBuffer::array
  )
);

long[] longs = new long[] { Long.MIN_VALUE, -1l, 0l, 1l, Long.MAX_VALUE };
Long[] boxedLongs = LongStream.of(longs).boxed().toArray(Long[]::new);
long[] collectedLongs = Stream.of(boxedLongs ).collect(
  Collector.of(
    () -> LongBuffer.allocate(boxedLongs .length), 
    LongBuffer::put, 
    LongBuffer::put, 
    LongBuffer::array
  )
);

double[] doubles = new double[] { Double.MIN_VALUE, -1.0, 0, 1.0, Double.MAX_VALUE };
Double[] boxedDoubles = DoubleStream.of(doubles)
  .boxed()
  .toArray(Double[]::new);
double[] collectedDoubles = Stream.of(boxedDoubles).collect(
  Collector.of(
    () -> DoubleBuffer.allocate(boxedDoubles.length), 
    DoubleBuffer::put, 
    DoubleBuffer::put, 
    DoubleBuffer::array
  )
);
Subplot answered 22/4, 2022 at 22:47 Comment(0)
G
-1

Here is a generic solution for all primitive types

/**
 * Convert Collection to equivalent array of primitive type
 * @param <S> [in] Element type of source collection
 * @param tcls [in] class of the primitive element
 * @param q [in] source collection
 * @return Equivalent Array of tcls-elements, requires cast to "tcls"[]
 */
public static <S> Object asPrimitiveArray(Class<?> tcls, Collection<S> q)
{
    int n = q.size();
    Object res = Array.newInstance(tcls, n);
    Iterator<S> i = q.iterator();
    int j = 0;
    while (i.hasNext())
    {
        Array.set(res, j++, i.next());
    }
    return res;
}

/**
 * Convert Object array to equivalent array of primitive type
 * @param <S> [in] Element type of source array
 * @param tcls [in] class of the primitive element
 * @param s [in] source array
 * @return Equivalent Array of tcls-elements, requires cast to "tcls"[]
 */
public static <S> Object asPrimitiveArray(Class<?> tcls, S[] s)
{
    return asPrimitiveArray(tcls, Arrays.asList(s));
} 

For Integer to int conversion

Integer[] a = ...
int[] t = (int[]) asPrimitiveArray(int.class, a);
Geter answered 14/7, 2021 at 17:28 Comment(0)
N
-1

Yes, we can convert Arrays of Objects to primitive, please refer below code. Java 8 is awesome at to learn java 8 skills in more detail I have got one youtube channel.

https://www.youtube.com/@thefullstackguy Happy Learning :)

private static int[] reverseJava8(int[] arr) {
    Object[] objects = Arrays.stream(arr)
            .boxed()
            .sorted(Comparator.reverseOrder())
            .toArray();
    return Arrays.stream(objects).mapToInt(i -> (int) i).toArray();

}
Nutmeg answered 8/3, 2023 at 5:12 Comment(1)
Why the reversing sort? OP didn't ask for that.Oxysalt

© 2022 - 2024 — McMap. All rights reserved.