2

I have a switch case on some enum type depending on which I am creating an array. It looks like:

switch (type) {
    case BOOLEAN:
        Boolean[] booleans = new Boolean[];
    case STRING:
        String[] strings = new String[];
}

I wonder is it possible to extract it to some method so it works like:

ArrayWrapper arrayWrapper = // some logic for which I am looking for

and then I have a generic method that accepts any type of array, and I would like to invoke it like method(arrayWrapper.getArray()); and it will be casted to specific type and processed by specific type processor?

fantaghirocco
  • 4,345
  • 6
  • 34
  • 46
Oleksandr Riznyk
  • 690
  • 1
  • 5
  • 17
  • nope, not really. Arrays can't be of a generic type - you can declare one like that, but you can't create one. – Eugene Mar 08 '19 at 11:12
  • 1
    Are you looking for an `Object[]` there? – Naman Mar 08 '19 at 11:26
  • 1
    Fully not sure what you're trying to do. (What's the relation to the "java-stream" tag?!) So you have an enum that defines which type of array *you* will create, so at that point *you* know what type the array is. Then you lose the information from the enum and later want to try and reconstruct it to basically do the same `switch(type)` on the array instances again? – JimmyB Mar 08 '19 at 11:45

3 Answers3

2

The java.lang.reflect.Array class provides functionality for working with any type of arrays, without knowing what type it is.

Using that class, you can write code like this:

public void example(Class<?> elemType) {
    Object[] arr = (Object[]) Array.newInstance(elemType, 10);

    // Do something with the array
}

(Don't cast to Object[] if you want to be able to work with arrays of primitive types.)

Array is part of the reflection system. That implies that you will have to used Class objects for element types, and probably have variables of Object type to refer to element values.

Lii
  • 9,906
  • 6
  • 53
  • 73
2

Java Generics combined with the Reflection API can be used in order to obtain an instance of T[]:

@SuppressWarnings("unchecked")
public static <T> T[] createArrayInstance(Class<T> clazz, int size) {
    return (T[])Array.newInstance(clazz, size);
}

If you want to store, for any reason, a value in the resulting array:

@SuppressWarnings("unchecked")
public static <T> T[] createArrayInstance(T obj) {
    T[] a = (T[])Array.newInstance(obj.getClass(), 1);//or whatever size you want
    a[0] = obj;
    return a;
}

See also: How to create a generic array in Java?

fantaghirocco
  • 4,345
  • 6
  • 34
  • 46
0

One possible way would be to bind the array's element type to a generic type parameter and tie the processor and the array together early on:

public class ArrayProcessingWrapper<T> {
  private final T[] array;
  private final ArrayProcessor<T> processor;

  public ArrayProcessingWrapper(T[] array, ArrayProcessor<T> processor) {
    super();
    this.array = array;
    this.processor = processor;
  }

  public void processArray() {
    this.processor.process(this.array);
  }

}

Another way might be along the lines of functions

public abstract class Processor<T> {
  private final Supplier<T[]> arraySupplier;

  public Processor(final Supplier<T[]> arraySupplier) {
    super();
    this.arraySupplier = arraySupplier;
  }

  public T[] createArray() {
    return this.arraySupplier.get();
  }

  public void processNewArray() {
    this.doProcess(this.createArray());
  }

  protected abstract void doProcess(T[] data);
}

public class BooleanProcessor extends Processor<Boolean> {
  public BooleanProcessor(Supplier<Boolean[]> arraySupplier) {
    super(arraySupplier);
  }

  @Override
  protected void doProcess(Boolean[] data) {
    // Do fancy boolean stuff...
  }
}

But also have a look at Iterable<E> and/or Collection<E> (of which ArrayList<E> is what behaves the most like an array) instead of arrays.

To me, it seems like a design flaw if you need to use different logic ("processors") depending on the (runtime) type of an array.

JimmyB
  • 11,178
  • 1
  • 23
  • 42