How to define a method that can take arbitrary arguments in java?
How to define a method that can take arbitrary arguments in java? Is t开发者_运维知识库here a demo?
varargs were introduced in Java 5.
For instance:
public String join(String... parts);
This is actually a shortcut for:
public String join(String[] parts);
the parts
parameter is used as an array in the method, but the method can be called without constructing an array (like obj.join(new String[] {part1, part2, part3})
)
However be very careful with this, because ambiguities can arise. For example:
public void write(String author, String... words);
public void write(String... words);
Which method will be called if obj.write("Mike", "jumps")
? The compiler is clever enough to detect the ambiguity, but I've had cases when some compilers did not spot such problems (can't recall exactly)
Using varargs is practical when the objects are of the same type, or at least with the same functional aim. If you want different arguments. For example:
public String publishBook(String title, [String author],
[String isbn], [boolean hardcover]); // [..] would mean optional
then you need to overload your method
Variable-Length Argument Lists
It doesn't work in the general case. Even if you define your Method as:
@SafeVarargs
public void callMe(Object... args) { ... }
When you call callMe(1, "hallo", 3.14159, new Object())
, this will work. However, if you want to have a similar method on an interface, you cannot use @SafeVarargs
, as it can only be added to final methods (lest they be overridden with an unsafe implementation).
The best you can do in that case is to define in your interface:
@SuppressWarnings("unchecked")
public <T> void callMe(T... args);
This will at least omit the warning, when callMe is called with objects of the same runtime type, e.g. `callMe("a", "b", "c"). However, a warning will appear when you call it with different types, as in the example above:
ArbitraryCallable x = new ArbitraryCallableImplementation();
x.callMe("a", "b"); // no warning
x.callMe(1, "x", 3.14159); // warning
And not to forget, since Object...
is nothing but syntactic sugar for Object[]
, you cannot simply call `callMe(new Object[] { "a" }), because this creates an ambiguous situation: Did you want to call callMe with one Object (which happens to be an array) or with the elements of the array?
Here is a simple tutorial about variable arguments. Sample code:
public void foo (ParamType ... name) {
}
For passing a variable number of arguments, you can use the varargs syntax (you specify a type followed by an ellipsis, and the so-named parameter is an array of the specified type, and Java will add some syntactic sugar so that you can pass in a list of any number of that type and it will automatically be put in the array).
For passing arbitrary types, one can use Java generics to allow arbitrary types or one can use type Object. It is generally better to use generics, because you get more type checking, but both will do.
- Varargs
- Generics
Here is an example of varargs:
public static void printAll(String... args){ for (String str : args ){ System.out.println(str); } } // Now can write printAll("Hello", "world", "etc", "etc");
Here is an example of generics:
public static <T> void print(T obj){ System.out.println(obj.toString()); }
I'm afraid java cannot do that out of the box just yet (in contrast with some other languages) even when you consider varargs (as they are really of one type only). However OO patterns are your friend and you can use the Builder pattern to accomplish what you require. A short example (stolen adapted and shortened from Effective Java 2nd Edition)
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val) {
calories = val;
return this;
}
public Builder fat(int val) {
fat = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
}
}
With this you can do something like
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
calories(100).fat(35).build();
Now the really cool thing about this, is that you can add methods that actually take varargs too, which makes this particular pattern very powerful. This pattern also makes your object immutable and saves you from writing telescoping constructors. What it won't do is your dishes but I live in hope ;)
精彩评论