tags:

views:

150

answers:

4

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.

A: 

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

Colin Hebert
I don't think the dependency is useless. The StringUtils.* methods are a huge time-saver. ArrayUtils is a bonus :-)
seanizer
@seanizer I totally agree, Commons lang is really useful, I just say that having a dependency to it for only one static method isn't.
Colin Hebert
@colin then I agree too
seanizer
We should just delete this answer at this point. @seanizer got it right.
Erick Robertson
@Erick I strongly disagree. Different viewpoints on a question are important
seanizer
It's cheaper to include StringUtils.* than to write code. What's another jar? Our projects have a ton already.
Tony Ennis
Well maybe soon it will be guava instead of commons / lang, but we're not there yet :-)
seanizer
+12  A: 

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);
seanizer
Nifty. Thank you!
BlairHippo
+1  A: 

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.

ColinD
I agree. Collections rule, arrays suck, guava rules (+1)
seanizer
A: 

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:

@SuppressWarnings("unchecked")
public static <T> T[] toWrapperArray(final Object primitiveArray){
    if(primitiveArray==null)
        throw new NullPointerException("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");
    T[] arr=null;
    for (int i = 0; i < length; i++) {
        final Object wrapped = Array.get(primitiveArray, i);
        if(arr==null){
            arr=(T[]) Array.newInstance(wrapped.getClass(), length);
        }
        arr[i]=(T) wrapped;
    }
    return arr;
}

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

  • There's no compile-time safety:
    1. 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
    2. The return type can be assigned to any Object array type, which will fail with a ClassCastException if you choose the wrong type.
  • 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 are two test methods. The first test the proper workings:

@Test
public void testWrappers() throws Exception {
    final Integer[] wrappedIntegers = toWrapperArray(
                new int[]{1,2,3});
    assertArrayEquals(new Integer[]{1,2,3},wrappedIntegers);
    final Long[] wrappedLongs = toWrapperArray(
                new long[]{1l,2l,3l});
    assertArrayEquals(new Long[]{1l,2l,3l},wrappedLongs);
    final Boolean[] wrappedBooleans = toWrapperArray(
                new boolean[]{true,false,false,true});
    assertArrayEquals(new Boolean[]{true,false,false,true},wrappedBooleans);
}

The second tests the expected failures:

@Test
public void testWrapperFailures(){
    try {
        final Object[] wrapped = toWrapperArray(null);
        fail("False positive with null value");
    } catch (final Exception e) {}
    try {
        final Object[] wrapped = toWrapperArray(
                    "Elvis has left the building");
        fail("False positive with non-Array object");
    } catch (final Exception e) {}
    try {
        final Object[] wrapped = toWrapperArray(
                    new String[]{"Elvis", "has", "left", "the", "building"});
        fail("False positive with non-primitive Array");
    } catch (final Exception e) {}
    try {
        final Long[] wrapped = toWrapperArray(new int[]{1,2,3});
        fail("False positive where ClassCastException should occur");
    } catch (final Exception e) {}
}

Of course it's not possible to create such a method the other way around without keeping a lookup table, or is there?

seanizer