Converting Array of Primitives to Array of Containers in Java
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.
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
- they are live views (i.e. updates to the array change the list and vice-versa)
- 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[]
.
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).
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.
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;
}
}