DrEnquinox
DrEnquinox

Reputation: 47

Pattern to circumvent code bloat with primitives in Java

Hello fellow Stackoverflowers,

I have the following problem:

I have a situation, where I get an array of primitive numbers as an input. For example int[] or short[] or even byte[]. Now, I need to iterate over the code and do certain stuff, for example, write the numbers into a list. The problem is, however, that every type of number needs a certain list. No problem, I thought, and tried to use generics:

Object dataSet = provider.getDataArray();
Number[] copy = new Number[Array.getLength(dataSet)];
for(int i= 0; i < Array.getLength(dataSet); i++) {
    copy[i] = (T) Array.get(dataSet, i);
}

This works beautifully. However, the problem is with performance. I know that is cannot be circumvented because Reflection and the occuring boxing of the primitives is costly. I am now searching for a pattern to reduce the amount of code, because writing

Object dataSet = provider.getDataArray();
Class<? extends Number> dataType = provider.getDataType();

Number[] copy = new Number[dataSet.length];
if(dataType == Float.class) 
    float[] dataSetAsFloat = (float[]) dataSet;
    for(int i= 0; i < dataSet.length; i++) 
        copySet[i] = dataSetAsFloat[i];
else if (dataType == Double.class)
    double[] dataSetAsDouble = (double[]) dataSet;
    for(int i= 0; i < dataSet.length; i++) 
        copySet[i] = dataSetAsFloat[i];    
....

is a very bloated solution, because the application in the program I'm writing is not as simple as shown here. Basically, I create several hundred lines of extra code because of this performance problem. Is there a solution to this? Perhaps a pattern I'm not aware of, or some really simple trick I'm not seeing?

I would be immensely grateful for a response.

Thanks.

Upvotes: 2

Views: 320

Answers (2)

Jeff Storey
Jeff Storey

Reputation: 57192

Have you considered a strategy pattern that chooses a conversion strategy based on the data type? While it won't reduce much of the overall total code, it will help to modularize it.

public interface ArrayConversionStrategy<T extends Number> {
    T[] convertArray
}

public class FloatConversionStrategy implements ArrayConversionStrategy<Float>
   float[] convertArray(Object[] dataset) {
     float[] dataSetAsFloat = new float[dataset.length];
      for(int i= 0; i < dataSet.length; i++) 
        dataSetAsFloat [i] = dataset[i];
  }
}

public class DoubleConversionStrategy { ... }
public class LongConversionStrategy { ... }

Then in the calling class have a map of data types to strategies

Map<Class<? extends Number>, ArrayConversionStrategy> map;

Object[] dataSet =    provider.getDataArray();
Class<? extends Number> dataType = provider.getDataType();
ArrayConversionStrategy strategy = map.get(dataType)
return strategy.convertArray(dataSet);

Some of my generic syntax may be off here and may have some boxing/autounboxing that may need to be done, but just as a general strategy this may be useful.

Upvotes: 1

Peter Lawrey
Peter Lawrey

Reputation: 533492

Instead of unpacking the wrapper, you can use a getLong(int)/putLong for integers and getDouble(int)/putDouble for floating point. This will give you two methods which support all primitives types.

interface Array {
    public long getLong(int idx);
    public double getDouble(int idx);
    public void setLong(int idx, long l);
    public void setDouble(int idx, double d);
}

class ByteProvider implements Array {

}

class IntProvider implement Array {

etc.

Upvotes: 0

Related Questions