Converting Array of Primitives to Array of Containers in Java

JavaArrays

Java Problem Overview


Is there an elegant way to turn an array of primitives into an array of the corresponding container objects -- turn a byte[] into a Byte[], for example? Or am I stuck with looping through it and doing it manually?

Yeah, the for loop isn't exactly difficult. Just kinda ugly.

Java Solutions


Solution 1 - Java

Apache Commons

Apache Commons / Lang has a class ArrayUtils that defines these methods.

  • All methods called toObject(...) convert from primitive array to wrapper array
  • All called toPrimitive(...) convert from wrapper object array to primitive array

Example:

final int[]     original        = new int[] { 1, 2, 3 };
final Integer[] wrappers        = ArrayUtils.toObject(original);
final int[]     primitivesAgain = ArrayUtils.toPrimitive(wrappers);
assert Arrays.equals(original, primitivesAgain);

Guava

But then I'd say that Arrays of wrapped primitives are not very useful, so you might want to have a look at Guava instead, which provides Lists of all numeric types, backed by primitive arrays:

List<Integer> intList = Ints.asList(1,2,3,4,5);
List<Long> longList   = Longs.asList(1L,2L,3L,4L,5L);
// etc.

The nice think about these array-backed collections is that

  1. they are live views (i.e. updates to the array change the list and vice-versa)
  2. the wrapper objects are only created when needed (e.g. when iterating the List)

See: Guava Explained / Primitives


Java 8

On the other hand, with Java 8 lambdas / streams, you can make these conversions pretty simple without using external libraries:

int[] primitiveInts = {1, 2, 3};
Integer[] wrappedInts = Arrays.stream(primitiveInts)
                              .boxed()
                              .toArray(Integer[]::new);
int[] unwrappedInts = Arrays.stream(wrappedInts)
                             .mapToInt(Integer::intValue)
                             .toArray();
assertArrayEquals(primitiveInts, unwrappedInts);

double[] primitiveDoubles = {1.1d, 2.2d, 3.3d};
Double[] wrappedDoubles = Arrays.stream(primitiveDoubles)
                                .boxed()
                                .toArray(Double[]::new);
double[] unwrappedDoubles = Arrays.stream(wrappedDoubles)
                                  .mapToDouble(Double::doubleValue)
                                  .toArray();

assertArrayEquals(primitiveDoubles, unwrappedDoubles, 0.0001d);

Note that the Java 8 version works for int, long and double, but not for byte, as Arrays.stream() only has overloads for int[], long[], double[] or a generic object T[].

Solution 2 - Java

You have to loop through your array.


Updated after @seanizer answer :

Basically the toObject(byte[] array) method will do the looping for you :

public static Byte[] toObject(byte[] array) {
    if (array == null) {
        return null;
    } else if (array.length == 0) {
        return EMPTY_BYTE_OBJECT_ARRAY;
    }
    final Byte[] result = new Byte[array.length];
    for (int i = 0; i < array.length; i++) {
        result[i] = new Byte(array[i]);
    }
    return result;
}

And unless you will really use the commons lang lib, you should simply reuse this method and avoid a useless dependency (IMHO).

Solution 3 - Java

Just to suggest an alternative, with Guava you can use one of the primitive type utilities such as Bytes or Ints to create a List of the wrapper type:

byte[] bytes = ...
List<Byte> byteList = Bytes.asList(bytes);

Rather than looping through and converting each byte, these methods actually create a list that is backed by the given array. If you really need a Byte[], this obviously doesn't directly give you what you need (though you can get it using .toArray(new Byte[bytes.length]) of course). Collections are vastly superior to arrays for objects, though, and should be preferred when possible.

Solution 4 - Java

Here is a short generic way of doing it without using any external libraries and it works for all primitives:

import static java.lang.reflect.Array.*;
import java.util.Arrays;

public class DeepConverter {

  public static void main(String args[]) {        
    long L1[][][] = {{{1,2},{3,4}}, {{5,6}}, {{7}},{{8,9,10,11}}};
    L1 = new long[2][0][7];
    Long L2[][] = (Long[][])box(L1);
    System.out.println(Arrays.deepToString(L2));        
  }

  public static Object box(Object src) {        
    try {
        int length = src.getClass().isArray() ? getLength(src) : 0;        
        if(length == 0)
            return src;        
        Object dest = newInstance(typeCastTo(wrap(get(src, 0))), length);        
        for(int i = 0; i < length; i++)
            set(dest, i, wrap(get(src, i)));        
        return dest;

    } catch(Exception e) {
        throw new ClassCastException("Object to wrap must be an array of primitives with no 0 dimensions");
    }
  }
    
  private static Class<?> typeCastTo(Object obj) {
    Class<?> type = obj.getClass();
    if(type.equals(boolean.class)) return Boolean.class;
    if(type.equals(byte.class)) return Byte.class;
    if(type.equals(char.class)) return Character.class;
    if(type.equals(double.class)) return Double.class;
    if(type.equals(float.class)) return Float.class;
    if(type.equals(int.class)) return Integer.class;
    if(type.equals(long.class)) return Long.class;
    if(type.equals(short.class)) return Short.class;
    if(type.equals(void.class)) return Void.class;        
    return type;
  }
}

Solution 5 - Java

> Is there an elegant way to turn an array of primitives into an array > of the corresponding container objects?

Suppose you have an array of bytes:

byte[] b = new byte[20];
... (fill b) ...

Then you can use Arrays.setAll(..) to convert it:

Byte[] w = new Byte[b.length];
Arrays.setAll(w, i -> b[i]);

Arrays.parallelSetAll(...) is even faster:

Arrays.parallelSetAll(w, i -> b[i]);

To verify the result:

System.out.println(b.getClass().getCanonicalName());
System.out.println(Arrays.toString(b));
System.out.println(w.getClass().getCanonicalName());
System.out.println(Arrays.toString(w));

If you need a universal wrapper for all kinds of primitive arrays, here it is:

public static Object[] wrap(Object a) {
	if (a == null)
		return null;
	int length = Array.getLength(a);
	Object b = length > 0 ? a : Array.newInstance(a.getClass().getComponentType(), 1);
	Object[] result = (Object[])Array.newInstance(Array.get(b, 0).getClass(), length);
	Arrays.parallelSetAll(result, i -> Array.get(a, i));
	return result;
}

Use it like this:

Byte[] w = (Byte[])wrap(b);

Solution 6 - Java

After adding a good answer, here's an awful answer, just for the heck of it. What bothers me about the Apache Commons ArrayUtils class is that there are 8 versions of the same method, just for different input types. I found a generic way to convert any primitive array into its wrapper equivalent (hence reducing the 8 different versions to one). This is the code:

public final class ArraysUtils {

    private ArraysUtils() {    }

    @SuppressWarnings("unchecked")
    public static Object[] toWrapperArray(final Object primitiveArray) {
        Objects.requireNonNull(primitiveArray, "Null values are not supported");
        final Class<?> cls = primitiveArray.getClass();
        if (!cls.isArray() || !cls.getComponentType().isPrimitive()) {
            throw new IllegalArgumentException(
                    "Only primitive arrays are supported");
        }
        final int length = Array.getLength(primitiveArray);
        if (length == 0) {
            throw new IllegalArgumentException(
                    "Only non-empty primitive arrays are supported");
        }
        final Object first = Array.get(primitiveArray, 0);
        Object[] arr = (Object[]) Array.newInstance(first.getClass(), length);
        arr[0] = first;
        for (int i = 1; i < length; i++) {
            arr[i] = Array.get(primitiveArray, i);
        }
        return arr;
    }

}

As you can see, there's quite a lot wrong with that method:

  • There's no compile-time safety, the method parameter can be anything and only the method itself will validate runtime parameters, rigorously rejecting null values, empty arrays, non-arrays and non-primitive arrays
  • Reflection was needed
  • There is no way to support empty arrays without keeping some sort of lookup table between primitive and wrapper classes.

Anyway, here is a test suite for all the necessary scenarios, using JUnit's Parameterized runner:

@RunWith(Parameterized.class)
public class ArraysUtilsTest {
    @Parameterized.Parameters(name = "{0}")
    public static List<Object> parameters() {
        return Arrays.asList(
                success(new int[]{1, 2, 3}, new Integer[]{1, 2, 3}),
                success(new long[]{1L, 2L, 3L}, new Long[]{1L, 2L, 3L}),
                success(new byte[]{1, 2, 3}, new Byte[]{1, 2, 3}),
                success(new short[]{1, 2, 3}, new Short[]{1, 2, 3}),
                success(new char[]{'a', 'b', 'c'}, new Character[]{'a', 'b', 'c'}),
                success(new double[]{1.0, 2.0, 3.0}, new Double[]{1.0, 2.0, 3.0}),
                success(new float[]{1.0f, 2.0f, 3.0f}, new Float[]{1.0f, 2.0f, 3.0f}),
                success(new boolean[]{true, false, true}, new Boolean[]{true, false, true}),
                failure(null, NullPointerException.class, "Null"),
                failure("foo", IllegalArgumentException.class, "Non-array"),
                failure(new String[]{"foo", "bar"}, IllegalArgumentException.class, "Non-primitive array"),
                failure(new int[0], IllegalArgumentException.class, "Empty array")


            );
    }

    private static Object[] success(Object primitiveArray, Object[] wrapperArray) {
        return new Object[]{
                primitiveArray.getClass().getCanonicalName(),
                primitiveArray, null, wrapperArray};
    }

    private static Object[] failure(Object input,
                                    Class<? extends RuntimeException> exceptionClass,
                                    String description) {
        return new Object[]{description, input, exceptionClass, null};
    }

    @Parameterized.Parameter(0)
    // only used to generate the test name
    public String scenarioName;

    @Parameterized.Parameter(1)
    public Object inputArray;

    @Parameterized.Parameter(2)
    public Class<? extends RuntimeException> expectedException;

    @Parameterized.Parameter(3)
    public Object[] expectedOutput;


    @Test
    public void runScenario() {
        try {
            Object[] wrapped = ArraysUtils.toWrapperArray(inputArray);
            if (expectedException != null) {
                fail(String.format("Expected %s to be thrown",
                                   expectedException.getSimpleName()));
            }
            assertThat(wrapped, is(equalTo(expectedOutput)));
        } catch (RuntimeException e) {
            if (expectedException == null) {
                fail(String.format("Expected no exception but got %swith message '%s'",
                                   e.getClass().getSimpleName(),
                                   e.getMessage()));
            }
            if(!expectedException.isInstance(e)){
                fail(String.format("Expected %s but got %s with message '%s'",
                                   expectedException.getSimpleName(),
                                   e.getClass().getSimpleName(),
                                   e.getMessage()));
            }
        }
    }


}

Solution 7 - Java

To convert a char[] to a Character[] array, we're first going to build a representative test ASCII char array from an IntStream, by using an accordingly size-allocated CharBuffer, inside a custom Collector (built from Supplier, Accumulator, Combiner and finisher Function):

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

Then, we can create an array from the standard printable ASCII range. Using .range() instead of .iterate() saves the need of limiting the resulting stream afterwards.

The iterated int values are cast to char each and mapped to a 'boxed' Character object stream, which is then collected into the test char[] array:

char[] asciiChars = IntStream.range(32, 127)
  .mapToObj(i -> (char)i)
  .collect(charArrayCollector);

Now, we can convert the ASCII char[] array, again using an IntStream. This surrogates a classic for loop, by iterating over the array's indices, mapping each contained char into stream of 'boxed' Character objects, finally creating the desired Character[] array in the terminal operation. Stream.iterate is just for demonstration of an alternative way:

Character[] characters = IntStream.range(0, asciiChars.length)
  .mapToObj(i -> Character.valueOf(chars[i]))
  .toArray(Character[]::new);

Character[] characters2 = Stream.iterate(0, i -> i += 1)
  .map(i -> asciiChars[i])
  .limit(asciiChars.length)
  .toArray(Character[]::new);

Edit: Other primitive type arrays can be converted similarly; here, the boxing occurs in the .mapToObj() intermediate operation, where the source array elements are extracted and mapped to their object counterparts:

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

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

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

For primitive values supported by the Stream API, the corresponding dedicated stream implementations and .boxed()can be used instead:

int[] ints = new int[] { Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE };
Integer[] integers = IntStream.of(ints)
  .boxed()
  .toArray(Integer[]::new);

long[] longs = new long[] { Long.MIN_VALUE, -1l, 0l, 1l, Long.MAX_VALUE };
Long[] boxedLongs = LongStream.of(longs)
  .boxed()
  .toArray(Long[]::new);

double[] doubles = new double[] { Double.MIN_VALUE, -1.0, 0, 1.0, Double.MAX_VALUE };
Double[] boxedDoubles = DoubleStream.of(doubles)
  .boxed()
  .toArray(Double[]::new);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBlairHippoView Question on Stackoverflow
Solution 1 - JavaSean Patrick FloydView Answer on Stackoverflow
Solution 2 - JavaColin HebertView Answer on Stackoverflow
Solution 3 - JavaColinDView Answer on Stackoverflow
Solution 4 - JavapathikritView Answer on Stackoverflow
Solution 5 - JavaJohn McClaneView Answer on Stackoverflow
Solution 6 - JavaSean Patrick FloydView Answer on Stackoverflow
Solution 7 - JavafozzybearView Answer on Stackoverflow