4

About Varargs, can i repeat the arguments in a group?

For instance, i want to allow users pass in:

myFunc(1, "one");
myFunc(1, "one", 2, "two");
myFunc(1, "one", 2, "two", 3, "three");

It seems impossible. But as mentioned in the docs, the varargs is in fact an array, in old implementation. i would like to know how was people do before varargs is invented. That might inspire us how to achieve the above scenario. We can regard my scenario as {int, String}... repeating afterall.

Thanks for any input :-)

Edit:

Thanks for all your inputs!

So, is it calling by myFunc(new wrap(1, "one"), new wrap(2, "two"), new wrap(3, "three")); is the old method?

Edit 2:

Well, nope. Thats my fault of confusion.

For

myFunc(1);
myFunc(1, 2);
myFunc(1, 2, 3);

the old way should be

myFunc(new int[]{1});
myFunc(new int[]{1, 2});
myFunc(new int[]{1, 2, 3});

As far as i can see, as the repeating arguments form an array. All its arguments has to be of the same type. It should be impossible to achieve the above calls in a simple way. For curiosity, i start thinking of the possibility of operator overloading ... (?)

midnite
  • 5,157
  • 7
  • 38
  • 52

4 Answers4

4

In this case, it seems to me that it's suitable to create a datastructure for your "pair", and then use that type as vararg argument to your method.

public void myFunc(Pair... pairs) {}

You could also use Object..., but I don't see any advantages in this case, since the arguments always come in pairs.

NilsH
  • 13,705
  • 4
  • 41
  • 59
  • Thanks @NilsH. However, upon usage, users have to do `myFunc(new Pair(1, "one"), new Pair(2, "two"), new Pair(3, "three");`, isnt it? Could it be shortened? Or use in a more convenient way? – midnite Apr 13 '13 at 10:05
  • 1
    Yes, you would have to do that. If you don't want that, you would have to use `Object...` and then check and cast the arguments inside your method instead. But that would open up for incorrect usage of your method, so I wouldn't recommended that. – NilsH Apr 13 '13 at 10:15
  • yup indeed. and using `Object...` cannot guard the number of arguments to be even, right? – midnite Apr 13 '13 at 10:19
3

There are good reasons to use the other solutions, but they all introduce a bit of clutter (to create all those objects) you might not want to subject the users of your library to.

You can shift the clutter to the inside of your method like so:

public void example(final Object... args) {
    if (args.length % 2 != 0)
        throw new IllegalArgumentException("int, String pairs are required, but there seems to be an odd one out");

    for (int i = 0; i < args.length; i += 2) {
        int a = (Integer) args[i];
        String b = (String) args[i + 1];

        System.out.printf("%d: %s\n", a, b);
    }
}

example(1, "Hello", 2, "Goodbye", 25, "Raptors will eat you!"); will then produce the following output:

1: Hello
2: Goodbye
25: Raptors will eat you!
Olathe
  • 1,885
  • 1
  • 15
  • 23
2

What about creating a wrapper class that wraps the two parameters together?

public class TwoParameter
{
    private int intValue;
    private String stringValue;

    public TwoParameter(int intValue, String stringValue)
    {
        this.intValue = intValue;
        this.stringValue = stringValue;
    }

    // getters and setters
}

and then use it like:

myFunc(new TwoParameter(1, "one"), new TwoParameter(2, "two"));

The signature of the method would be something like this:

public void myFunc(TwoParameter... params){...}
Hendrik Brummermann
  • 8,242
  • 3
  • 31
  • 55
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
  • Thanks @Eng.Fouad. What i concern most is, upon calling, `myFunc(new TwoParameter(1, "one"), new TwoParameter(2, "two"));` seems to "long" and complicated. Is it possible to shorten it somehow? – midnite Apr 13 '13 at 10:13
2

Var args were introduced to allow you to send an arbitrary number of arguments to a function. Folks hacked around with other Collections / arrays before they came about.

You can achieve what you want with a custom structure. The particulars of the structure will depend on what the name value pair should achieve. Here is a generic solution for any NameValue pair.

NameValuePair

class NameValuePair<K,V>
{
    private K key;
    private V value;
    public K getKey()
    {
        return key;
    }
    public void setKey(K key)
    {
        this.key = key;
    }
    public V getValue()
    {
        return value;
    }
    public void setValue(V value)
    {
        this.value = value;
    }
}

Usage

private <K,V> void method(NameValuePair<K, V>... pairs )
{
    for (NameValuePair<K, V> nameValuePair : pairs)
    {
        K key = nameValuePair.getKey();
        V value = nameValuePair.getValue();
        // logic goes here 
    }
}
Community
  • 1
  • 1
Deepak Bala
  • 11,095
  • 2
  • 38
  • 49
  • Thanks @Deepak Bala. While my library users use it, they still have to do `NameValuePair nvp = new NameValuePair(); nvp.setKey(1); nvp.setValue("one"); method(nvp, nvp, nvp);`, isnt it? Is it possible to write less code and let users call the `method` like the example in my question? - It seems more user-friendly. – midnite Apr 13 '13 at 10:12
  • Java is strongly typed, so the only way to achieve what you want is to use `Object... args`. While this works out nicely for the caller, the method implementation will look dirty since it will need an `instanceof` to determine type. I'd stick with making it a little harder for the caller instead of writing dirty code with `instanceof`. – Deepak Bala Apr 13 '13 at 10:17
  • You're welcome. BTW using an `Object...` means that you cannot guarantee name value pairs :) – Deepak Bala Apr 13 '13 at 10:25