0

I want to convert the primitive type array to its respective boxed one, for example if I have an array of type int[] I would like to convert it to Integer[], and the same is to apply on long[], byte[], boolean[] , etc... I came up with this:

public static Integer[] toBoxedArray(int[] array) {
    Integer[] boxedArray = null;
    if (array != null) {
        boxedArray = new Integer[array.length];
        for (int i = 0; i < array.length; i++) {
            boxedArray[i] = array[i];
        }
    }
    return boxedArray;
}

The above method is repeated (a polymorphism) for all the primitive types.

The use of these methods requires many conditional blocks:

public static List castArrayToList(Object array) {
    List list = null;
    if (array instanceof int[]) {
        list = Arrays.asList(toBoxedArray((int[]) array));
    } else if (array instanceof long[]) {
        list = Arrays.asList(toBoxedArray((long[]) array));
    } else if (array instanceof byte[]) {
        list = Arrays.asList(toBoxedArray((byte[]) array));
    } else if (array instanceof boolean[]) {
        list = Arrays.asList(toBoxedArray((boolean[]) array));
    } else if (array instanceof float[]) {
        list = Arrays.asList(toBoxedArray((float[]) array));
    } else if (array instanceof short[]) {
        list = Arrays.asList(toBoxedArray((short[]) array));
    } else if (array instanceof double[]) {
        list = Arrays.asList(toBoxedArray((double[]) array));
    } else if (array instanceof char[]) {
        list = Arrays.asList(toBoxedArray((char[]) array));
    } else if (array instanceof Collection) {
        list = new ArrayList((Collection) array);
    }
    return list;
}

My question is this: is there a way to reduce the number of if's in the castArrayToList method ?

EDIT

the castArrayToList method takes Object as parameter, since the input comes from a reflective invokation.

Mustapha Belmokhtar
  • 1,231
  • 8
  • 21
  • 1
    How does the first part of your question relate to the second part? – T.J. Crowder Aug 03 '18 at 10:59
  • @TimBiegeleisen I don't think it's a duplicate, since my question is not how to convert `int[]`to `Integer[]`, what I provided is just an example of use – Mustapha Belmokhtar Aug 03 '18 at 11:01
  • *"the castArrayToList method takes Òbject` as parameter, since the imput comes from a reflective invokation"* That doesn't matter, you can invoke methods with parameters of a type other than `Object`. – T.J. Crowder Aug 03 '18 at 11:03
  • yeah, but I still have to do the cast every time I want to invokde the right method – Mustapha Belmokhtar Aug 03 '18 at 11:06
  • You could check this out : https://stackoverflow.com/questions/754294/convert-an-array-of-primitive-longs-into-a-list-of-longs – dbl Aug 03 '18 at 12:51

2 Answers2

2

My question is this: is there a way to reduce the number of if's in the castArrayToList method ?

Yes: Use overloads of castArrayToList instead, just as you did with toBoxedArray, so the compiler dispatches to the correct method for you:

public static List castArrayToList(int[] array) {
    return Arrays.asList(toBoxedArray(array));
}
public static List castArrayToList(long[] array) {
    return Arrays.asList(toBoxedArray(array));
}
public static List castArrayToList(byte[] array) {
    return Arrays.asList(toBoxedArray(array));
}
public static List castArrayToList(boolean[] array) {
    return Arrays.asList(toBoxedArray(array));
}
// ...and so on...
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • @мυѕτавєւмo - Right. Just like `Arrays` does when it has to accept arrays of primitives (`binarySearch`, `copyOf`, ...). – T.J. Crowder Aug 03 '18 at 11:05
  • Yeah, taht's it, I wanted to avoid the plenty of overloads I already have. – Mustapha Belmokhtar Aug 03 '18 at 11:07
  • 1
    @мυѕτавєւмo - These are basically your options: 1. Lots of `instanceof` checks (not generally best practice). 2. Lots of overloads. 3. Use reflection to determine the element type of the array and use the name of that type as a key to a map of the equivalent boxed type and use reflection to create the new array. Personally, given how few overloads are actually needed, I'd prefer #2. – T.J. Crowder Aug 03 '18 at 11:08
  • Right, I don't prefer the reflection choice too, still the overload is the key, but as I said, I should cast to the right type at every time I want to call that overloaded methods – Mustapha Belmokhtar Aug 03 '18 at 11:11
  • @мυѕτавєւмo - No, the compiler will pick the right method, you shouldn't need casting. At this point we're pretty far from the original question. If you think you need casting with the overloads, post a new question with a [mcve] of the situation and someone will show you why casting isn't needed. – T.J. Crowder Aug 03 '18 at 11:57
1

Using a Map we can implement a solution which doesn't use if at all.

public class Boxing {

  private static final Map<Class<?>, Function> MAPPER = createMapper();

  private static Map<Class<?>, Function> createMapper() {
    Map<Class<?>, Function> mapper = new HashMap<>();
    mapper.put(int[].class, toBoxedIntArray());
    mapper.put(long[].class, toBoxedLongArray());
    // TODO put mapping functions for remaining primitive array types
    return mapper;
  }

  @SuppressWarnings("unchecked")
  public static <T> T[] toBoxedArray(Object array) {
    if (array == null || !array.getClass().isArray() || !array.getClass().getComponentType().isPrimitive()) {
      return null;
    }

    return (T[]) MAPPER.get(array.getClass()).apply(array);
  }

  private static Function<int[], Integer[]> toBoxedIntArray() {
    return array -> {
      Integer[] boxed = new Integer[array.length];
      Arrays.setAll(boxed, index -> Integer.valueOf(array[index]));
      return boxed;
    };
  }

  private static Function<long[], Long[]> toBoxedLongArray() {
    return array -> {
      Long[] boxed = new Long[array.length];
      Arrays.setAll(boxed, index -> Long.valueOf(array[index]));
      return boxed;
    };
  }

  // TODO implement mapping functions for remaining primitive array types

  public static <T> List<T> castArrayToList(Object array) {
    T[] boxedArray = toBoxedArray(array);
    return boxedArray != null ?
      Arrays.asList(boxedArray) :
      null;
  }

  public static List castArrayToList(Collection collection) {
    return new ArrayList<>(collection);
  }

}

This can be used as follows for example:

  public static void main(String[] args) {
    int[] intArr = new int[] { 0, 1, 2 };
    Integer[] boxed = toBoxedArray(intArr);
    System.out.println(boxed); // [Ljava.lang.Integer;34340fab
    System.out.println(toBoxedArray(boxed)); // null
    System.out.println(castArrayToList(intArr)); // [0, 1, 2]
    System.out.println(castArrayToList(boxed)); // null
  }

Using the class as key of the MAPPER-Map works like an instanceof and replaces therefore the bunch of if-statements.

Please note that there are two methods castArrayToList. One which is intended to process primitive arrays and an additional one which takes a Collection. I added the latter one to reflect the behavior of castArrayToList shown in the question which will return a List if the given object is a Collection.

For the sake of completeness: Another way to literally get rid of if would be to use a switch-statement on array.getClass().getSimpleName(). But the resulting method would be similar bulky.

LuCio
  • 5,055
  • 2
  • 18
  • 34