2

I need to pass a dynamic list of primitives to a Java method. That could be (int, int, float) or (double, char) or whatever. I know that's not possible, so I was thinking of valid solutions to this problem.

Since I am developing a game on Android, where I want to avoid garbage collection as much as possible, I do not want to use any objects (e.g. because of auto boxing), but solely primitive data types. Thus a collection or array of primitive class objects (e.g. Integer) is not an option in my case.

So I was thinking whether I could pass a class object to my method, which would contain all the primitive vales I need. However, thats neither a solution to my problem, because as said the list of primitives is variable. So if I would go that way in my method I then don't know how to access this dynmic list of primitives (at least not without any conversion to objects, which is what I want to avoid).

Now I feel a bit lost here. I do not know of any other possible way in Java how to solve my problem. I hope that's simply a lack of knowledge on my side. Does anyone of you know a solution without a conversion to and from objects?

thkala
  • 84,049
  • 23
  • 157
  • 201
Matthias
  • 9,817
  • 14
  • 66
  • 125
  • 1
    Are you certain you're not optimizing too soon in your project? You could pass three arrays of the three different types. Pass a fourth array of type indicators. Then pull the values from the appropriate offset into the array of that given type. – Marvo Dec 02 '11 at 00:06
  • 1
    Frankly I don't think that I am optimizing too soon, because I already know that in my project I have to call this method very often. And I also know already that unfortunately auto (un)boxing that often does trigger the garbage collector way too much. – Matthias Dec 02 '11 at 00:15
  • Can you explain why you need this requirement? I've written quite a few games in Java and this has never been necessary for me so I'm pretty sure there is a workaround that avoids allocations. – mikera Dec 02 '11 at 03:14
  • @mikera: please have a look here under "Avoid Creating Unnecessary Objects" here: http://developer.android.com/guide/practices/design/performance.html – Matthias Dec 02 '11 at 08:40

6 Answers6

1

It would perhaps be useful to provide some more context and explain on exactly what you want to use this technique for, since this will probably be necessary to decide on the best approach.

Conceptually, you are trying to do something that is always difficult in any language that passes parameters on a managed stack. What do you expect the poor compiler to do? Either it lets you push an arbitrary number of arguments on the stack and access them with some stack pointer arithmetic (fine in C which lets you play with pointers as much as you like, not so fine in a managed language like Java) or it will need to pass a reference to storage elsewhere (which implies allocation or some form of buffer).

Luckily, there are several ways to do efficient primitive parameter passing in Java. Here is my list of the most promising approaches, roughly the order you should consider them:

  • Overloading - have multiple methods with different primitive arguments to handle all the possible combinations. Likely to be the the best / simplest / most lightweight option if there are a relatively small number of arguments. Also great performance since the compiler will statically work out which overloaded method to call.
  • Primitive arrays - Good way of passing an arbitrary number of primitive arguments. Note that you will probably need to keep a primitive array around as a buffer (otherwise you will have to allocate it when needed, which defeats your objective of avoiding allocations!). If you use partially-filled primitive arrays you will also need to pass offset and/or count arguments into the array.
  • Pass objects with primitive fields - works well if the set of primitive fields is relatively well known in advance. Note that you will also have to keep an instance of the class around to act as a buffer (otherwise you will have to allocate it when needed, which defeats your objective of avoiding allocations!).
  • Use a specialised primitive collection library - e.g. the Trove library. Great performance and saves you having to write a lot of code as these are generally well designed and maintained libraries. Pretty good option if these collections of primitives are going to be long lived, i.e. you're not creating the collection purely for the purpose of passing some parameters.
  • NIO Buffers - roughly equivalent to using arrays or primitive collections in terms of performance. They have a bit of overhead, but could be a better option if you need NIO buffers for another reason (e.g. if the primitives are being passed around in networking code or 3D library code that uses the same buffer types, or if the data needs to be passed to/from native code). They also handle offsets and counts for you which can helpful.
  • Code generation - write code that generates the appropriate bytceode for the specialised primitive methods (either ahead of time or dynamically). This is not for the faint-hearted, but is one way to get absolutely optimal performance. You'll probably want to use a library like ASM, or alternatively pick a JVM language that can easily do the code generation for you (Clojure springs to mind).
mikera
  • 105,238
  • 25
  • 256
  • 415
  • Thanks, especially the last idea might be interesting. Since I am writing a framework, that should and will be used in more than one application (which the reason for this problem anyway), it might be worth the effort. I will check that out! – Matthias Dec 02 '11 at 08:49
  • No problem - just be warned that the last method is very tough/complex to get right. If you're not careful it can make life difficult for users of your framework too. Make sure you really really need it before you go down that path! – mikera Dec 02 '11 at 09:09
0

There simply isn't. The only way to have a variable number of parameters in a method is to use the ... operator, which does not support primitives. All generics also only support primitives.

The only thing I can possibly think of would be a class like this:

class ReallyBadPrimitives {
    char[] chars;
    int[] ints;
    float[] floats;
}

And resize the arrays as you add to them. But that's REALLY, REALLY bad as you lose basically ALL referential integrity in your system.

I wouldn't worry about garbage collection - I would solve your problems using objects and autoboxing if you have to (or better yet, avoiding this "unknown set of input parameters" and get a solid protocol down). Once you have a working prototype, see if you run into performance problems, and then make necessary adjustments. You might find the JVM can handle those objects better than you originally thought.

corsiKa
  • 81,495
  • 25
  • 153
  • 204
  • First, I can't avoid the unknown set of input parameters, because I am writing a framework that has to support an undefined set of primitive values (which is in fact exactly the purpose of this framework). Second, unfortunately I have to worry about garbage collection. Until Android 2.2 the GC does significantly drop the frame rate in fast OpenGL applications if called to often. And in my case that would happen because in the game this method in question is called very often... – Matthias Dec 02 '11 at 00:19
  • @Matthias The point is that until you code it up and profile it you don't know if it's a problem. It should be easy to code up to see if it is a problem or not. – corsiKa Dec 02 '11 at 00:32
  • I do already know that tmp. object creation is indeed a problem under Android, at least in games where the frame count matters. Please have a look here: http://developer.android.com/guide/practices/design/performance.html – Matthias Dec 02 '11 at 08:42
0

Try to use the ... operator:

static int sum (int ... numbers)
        {
           int total = 0;
           for (int i = 0; i < numbers.length; i++)
                total += numbers [i];
           return total;
        }
Anthea
  • 3,741
  • 5
  • 40
  • 64
0

You can use BitSet similar to C++ Bit field. http://docs.oracle.com/javase/1.3/docs/api/java/util/BitSet.html

Rafał
  • 582
  • 1
  • 9
  • 14
0

You could also cast all your primitives to double then just pass in an array of double. The only trick there is that you can't use the boolean type.

0

Fwiw, something like sum(int... numbers) would not autobox the ints. It would create a single int[] to hold them, so there would be an object allocation; but it wouldn't be per int.

public class VarArgs {
    public static void main(String[] args) {
        System.out.println(variableInts(1, 2));
        System.out.println(variableIntegers(1, 2, 3));
    }   

    private static String variableInts(int... args) {
        // args is an int[], and ints can't have getClass(), so this doesn't compile
        // args[0].getClass();
        return args.getClass().toString() + " ";
    }   

    private static String variableIntegers(Integer... args) {
        // args is an Integer[], and Integers can have getClass()
        args[0].getClass();
        return args.getClass().toString();
    }   
}

output:

class [I 
class [Ljava.lang.Integer;
yshavit
  • 42,327
  • 7
  • 87
  • 124