Is it considered a good programing idiom to use Java varargs as an optional parameter?
Even more: if I have an interface, and some implementations need the additional parameter, and some don't, is it okay to use varargs in the method signature for the optional parameter?
In Java it is possible to use the following idiom:
public static void x(String ... strings)
which gets an array of strings, possibly empty. You could call it with
x() (empty array), x("1","2","3") etc
Varargs is usually used when you don't know the number of arguments of a "particular type" that the users of the api will like to pass. I don't think there is any problem with that since the user can decide to pass any number of parameter or not to pass any at all. For eg
public class NewClass {
public void print(String... a) {
System.out.println(a);
}
public static void main(String[] args) {
new NewClass().print();
}
}
Doen't hurt. Since you know the type of in the varargs.
I would say no. Using a varargs will allow any number of arguments to be provided for your optional parameter. How will you communicate to people implementing your interface or calling your method that only one value is expected? What should the behavior be when multiple values are provided? These are unnecessary complications.
If your method requires exactly 0 or 1 value for the optional argument, then you should use a language construct that only allows 0 or 1 value to be provided. It would be more appropriate to overload the method signature or allow the optional parameter to be null.
I don't think it is a good idea to use varargs to implement optional parameters.
Animal a = new Dog();
a.speak("bow");
You have no idea looking at the reference in above example what arguments should be applied as you may not know that it is a dog if the animal was extracted from say a List of animals.
As said by #Oli explicit overload is a good approach instead.
Related
This is my first code:
public class MethodReference {
public static void main (String []args) {
Stream<String> s = Stream.of("brown bear", "grizzly");
s.sorted(Comparator.reverseOrder()).forEach(System.out::print);
//...
}
}
Result: grizzlybrown bear
This is my second code:
public class MethodReference {
public static void main (String []args) {
Stream<String> s = Stream.of("brown bear", "grizzly");
s.sorted(Comparator::reverseOrder()).forEach(System.out::print);
//...
}
}
Result: compiler error
My questions:
Why is there a compiler error in the second code?
Can't I use the method reference for static method of functional interface?
I know I can't use method reference with default method of functional interface.
I know I can use method reference with a class in 5 cases:
Class
Class::staticMethod
Class::instanceMethod
instance::instanceMethod
Class::new
Functional Interface
Interface::abstractMethod
Thanks a lot!
Comparator.reverseOrder() is an expression which resolves to the Comparator type, because that's what it returns.
Comparator::reverseOrder is an expression which resolves to a method which takes no arguments and returns a Comparator e.g. a Supplier<Comparator<String>>, though it could be any matching functional interface.
In the second instance you are trying to pass a method (which provides a Comparator) as an argument. The method doesn't want that - it just wants the Comparator itself.
You could think of it like this (just pseudo-code to demonstrate the point):
s.sorted(new Comparator())
vs
s.sorted(new Supplier(new Comparator()))
To answer your second question as to whether it's ever possible to use a method reference for a static method of an interface - yes, absolutely!
If we declare the following method:
<T> void giveMeAComparatorSupplier(Supplier<Comparator<T>> supplier) { }
then we can definitely call it with a method reference
giveMeAComparatorSupplier(Comparator::reverseOrder);
(And FYI your method reference syntax is wrong - it never uses ())
Two things are wrong with your second code. First, method references do not use parentheses or arguments at all. You would need to supply only the method that would be called later; you are not calling the method at that point.
Second, the sorted method takes a Comparator, not a functional interface that would supply a Comparator. The method needs a Comparator already created and ready to go, not a functional interface that will supply a Comparator when needed.
It has nothing to do with the fact that Comparator is an interface; one can generally create a method reference to a static interface method. It has everything to do with the fact that sorted needs an actual Comparator instance and not an instance of a functional interface, which is when you could supply a method reference.
So even if you take off the parentheses, it still won't compile. Only your first code, which directly passes a Comparator, will compile and work as expected.
FXML-View:
....
<GridPane...>
<PersonController... />
</GridPane...>
....
Class PersonController:
public PersonController(Person... personsToExclude) {
FXMLLoader.load("PersonControllerView.fxml")
this.personsToExclude = personsToExclude;
}
This code sample leads to an excpetion, because the class cannot be invoked without a default constructor (by the FXMLLoader). Now my question: You CAN use this constructor as default constructor. You can create such an object like this:
PersonConstructor pc = new PersonConstructor(); // This calls the upper constructor
Why isn't reflection able to use this constructor too? Varargs appear to be arrays internally which will be null by default if no parameter was handed over.
Was this design decision solely made to reduce complexity (it actually does reduce it a little bit for the reader) or are there any other reasons why it is important to still have a "real" default constructor?
If Oliver Charlesworth is correct, your question is really:
Why doesn't Class#newInstance() work when the class doesn't have a zero-args constructor but does have a constructor accepting a single varargs argument?
If so, I don't think we can properly answer it unless there's a quote from the design process around adding varargs to Java.
We can speculate. My speculation is: Simplicity
newInstance() is older than varargs. Until varargs were added to the language, there was no ambiguity: It could only call the nullary (zero-arguments) constructor. So they may have felt that extending it to handle constructors accepting one varargs argument was code bloat and/or scope creep for the method. After all, if you really want to do that, you can look up the relevant constructor and call that instead.
Alternately, they may have felt that newInstance's documentation ruled out calling such a constructor. Let's look at the JavaDoc for newInstance():
Creates a new instance of the class represented by this Class object. The class is instantiated as if by a new expression with an empty argument list. The class is initialized if it has not already been initialized.
Note that this method propagates any exception thrown by the nullary constructor, including a checked exception...
The first paragraph supports the idea that it could call a constructor with just one varargs argument. The second paragraph, though, mentions a "nullary" constructor specifically (though in passing). A "nullary" constructor is a zero-argument constructor, specifically, not just a constructor that can be called with no arguments.
Doing so would markedly complicate newInstance(), because rather than just looking for a constructor that accepts no arguments, it would need to look through all the constructors for one that accepts a single argument where isVarArgs is true.
Changing newInstance() to do what you're suggesting adds a new error mode: It's perfectly possible for your PersonConstructor class to have more than one constructor that can be called via new PersonConstructor():
public class PersonConstructor
{
public PersonConstructor(String... args) {
}
public PersonConstructor(Person... args) {
}
}
So which one should newInstance call? It can't decide, so it would have to throw, throwing a new error it hadn't thrown prior to the addition of varargs to the language.
All in all, if I were on the team making the decision, I would also have had newInstance() only consider true nullary constructors and not constructors accepting a single varargs argument. (I would also have updated the JavaDoc to say that. :-) )
Variable argument lists are implemented entirely in the compiler. Methods that take arrays and methods that take vararg arrays are compatible with each other - for example, you can use vararg signature
void foo(String... args)
to override a non-vararg signature
void foo(String[] args)
and vice versa (demo).
Was this design decision solely made to reduce complexity?
It is hard to guess why this particular design decision has been made, but at least part of the reason can be attributed to designer's reluctance to make changes to libraries and JVM. Java 5 update, in which variable argument feature has been introduced, opted for full backward compatibility on the bytecode level, despite the fact that it was a very big update, which introduced generics.
If you would like to work around this limitation, implement a no-argument constructor that routs the call to the constructor which takes an array:
public PersonController(Person... personsToExclude) {
}
public PersonController() {
this(new Person[0]);
}
Varargs appear to be arrays internally which will be null by default if no parameter was handed over.
This is not true. If you call a vararg method (or constructor) without any argument, the method (or constructor) is still a method with one array argument. And not null will be passed, but an empty array, as Oliver already has pointed out.
So the answer is: A vararg constructor has definitely one argument, and so it cannot be a default constructor.
I have been writing java for a while, and today I encountered the following declaration:
public static void main(String... args) {
}
Note the "dot dot dot" in the array declaration, rather than the usual bracket []. Clearly it works. In fact I wrote a small test and verified it works. So, I pulled the java grammar to see where this syntax of argument declaration is, but did not find anything.
So to the experts out there, how does this work? Is it part of the grammar? Also, while I can declare function like this, I can't declare an array within a function's body like this.
Anyway, do you know of any place that has this documented. It is curiosity, and perhaps not worth of any time invested in it, but I was stumped.
I believe this was implemented in Java 1.5. The syntax allows you to call a method with a comma separated list of arguments instead of an array.
public static void main(String... args);
main("this", "is", "multiple", "strings");
is the same as:
public static void main(String[] args);
main(new String[] {"this", "is", "multiple", "strings"});
http://today.java.net/article/2004/04/13/java-tech-using-variable-arguments
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
Check out the Java Language Specification, Third Edition, Chapter 8 (Classes). Buried in there is this nugget:
If the last formal parameter is a variable arity parameter of type T, it is considered to define a formal parameter of type T[]. The method is then a variable arity method. Otherwise, it is a fixed arity method. Invocations of a variable arity method may contain more actual argument expressions than formal parameters. All the actual argument expressions that do not correspond to the formal parameters preceding the variable arity parameter will be evaluated and the results stored into an array that will be passed to the method invocation (§15.12.4.2).
Basically, the last parameter of any method call can have T.... If it has that, it is converted to T[].
So basically, what you have is a fancy way of reproducing the more traditional
String[] args
It is varargs
In simple term its an Array of Member like
public setMembers(Member[] members);
When to use:
Generally while designing API it is good to use when number of argument is not fixed.
Example from standard API of this is String.format(String format,Object... args)
Also See
var-arg-of-object-arrays-vs-object-array-trying-to-understand-a-scjp-self-test
This is called variadic arguments, check here:
http://en.wikipedia.org/wiki/Variadic_function#Variadic_functions_in_C.23.2C_C.2B.2B.2FCLI.2C_VB.net.2C_and_Java
The official documentation (Java 1.5) is here:
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
It's the so-called varargs syntax. In the method body, you can read the members parameter as it were an array - actually, it /is/ 'just' an array.
However, the magic bit is in calling the method. Before the varargs syntax was introduced, you'd call the method a bit like so:
setMembers(new Members[] {member1, member2, member3});
With the new varargs syntax however, you don't need to explicitly create the array anymore, and you can pass:
setMembers(member1, member2, member3);
This does mean however that a varargs argument has to be the last argument in a method. Something like this is therefore not permitted:
void setMembers(Member ... members, String memberType);
Summarized: It's a bit of syntactic sugar, really. I'm no expert on the inner workings of the Java compiler, but I'm pretty sure that methods calling a method that accept a varargs parameter are rebuilt into methods that build an array of the given type.
You might want to read up on Using Variable Arguments (or varargs) in Java.
It's called varadic argument: A function that takes as many (including zero) arguments as you want.
For example, main("string1", "string2", "string3") is same as main({"string1", "string2", "string3"}) if main is declared as void main(String...args).
See http://www.java-tips.org/blog/java-se/varargs-%E2%80%93-java-50-addition.html
It means you can pass zero or more Member objects to the setMembers() method. In the setMembers method, members will have array semantics.
Variable arguments. Can have 0 or more String arguments.
The function can access the parameters as an array of Strings.
It means that the method accepts a variable number of String arguments. The arguments are treated as an array and so are accessed by subscript, in the order they are passed in.
I have been writing java for a while, and today I encountered the following declaration:
public static void main(String... args) {
}
Note the "dot dot dot" in the array declaration, rather than the usual bracket []. Clearly it works. In fact I wrote a small test and verified it works. So, I pulled the java grammar to see where this syntax of argument declaration is, but did not find anything.
So to the experts out there, how does this work? Is it part of the grammar? Also, while I can declare function like this, I can't declare an array within a function's body like this.
Anyway, do you know of any place that has this documented. It is curiosity, and perhaps not worth of any time invested in it, but I was stumped.
I believe this was implemented in Java 1.5. The syntax allows you to call a method with a comma separated list of arguments instead of an array.
public static void main(String... args);
main("this", "is", "multiple", "strings");
is the same as:
public static void main(String[] args);
main(new String[] {"this", "is", "multiple", "strings"});
http://today.java.net/article/2004/04/13/java-tech-using-variable-arguments
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
Check out the Java Language Specification, Third Edition, Chapter 8 (Classes). Buried in there is this nugget:
If the last formal parameter is a variable arity parameter of type T, it is considered to define a formal parameter of type T[]. The method is then a variable arity method. Otherwise, it is a fixed arity method. Invocations of a variable arity method may contain more actual argument expressions than formal parameters. All the actual argument expressions that do not correspond to the formal parameters preceding the variable arity parameter will be evaluated and the results stored into an array that will be passed to the method invocation (§15.12.4.2).
Basically, the last parameter of any method call can have T.... If it has that, it is converted to T[].
So basically, what you have is a fancy way of reproducing the more traditional
String[] args
It is varargs
In simple term its an Array of Member like
public setMembers(Member[] members);
When to use:
Generally while designing API it is good to use when number of argument is not fixed.
Example from standard API of this is String.format(String format,Object... args)
Also See
var-arg-of-object-arrays-vs-object-array-trying-to-understand-a-scjp-self-test
This is called variadic arguments, check here:
http://en.wikipedia.org/wiki/Variadic_function#Variadic_functions_in_C.23.2C_C.2B.2B.2FCLI.2C_VB.net.2C_and_Java
The official documentation (Java 1.5) is here:
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
It's the so-called varargs syntax. In the method body, you can read the members parameter as it were an array - actually, it /is/ 'just' an array.
However, the magic bit is in calling the method. Before the varargs syntax was introduced, you'd call the method a bit like so:
setMembers(new Members[] {member1, member2, member3});
With the new varargs syntax however, you don't need to explicitly create the array anymore, and you can pass:
setMembers(member1, member2, member3);
This does mean however that a varargs argument has to be the last argument in a method. Something like this is therefore not permitted:
void setMembers(Member ... members, String memberType);
Summarized: It's a bit of syntactic sugar, really. I'm no expert on the inner workings of the Java compiler, but I'm pretty sure that methods calling a method that accept a varargs parameter are rebuilt into methods that build an array of the given type.
You might want to read up on Using Variable Arguments (or varargs) in Java.
It's called varadic argument: A function that takes as many (including zero) arguments as you want.
For example, main("string1", "string2", "string3") is same as main({"string1", "string2", "string3"}) if main is declared as void main(String...args).
See http://www.java-tips.org/blog/java-se/varargs-%E2%80%93-java-50-addition.html
It means you can pass zero or more Member objects to the setMembers() method. In the setMembers method, members will have array semantics.
Variable arguments. Can have 0 or more String arguments.
The function can access the parameters as an array of Strings.
It means that the method accepts a variable number of String arguments. The arguments are treated as an array and so are accessed by subscript, in the order they are passed in.
I have been writing java for a while, and today I encountered the following declaration:
public static void main(String... args) {
}
Note the "dot dot dot" in the array declaration, rather than the usual bracket []. Clearly it works. In fact I wrote a small test and verified it works. So, I pulled the java grammar to see where this syntax of argument declaration is, but did not find anything.
So to the experts out there, how does this work? Is it part of the grammar? Also, while I can declare function like this, I can't declare an array within a function's body like this.
Anyway, do you know of any place that has this documented. It is curiosity, and perhaps not worth of any time invested in it, but I was stumped.
I believe this was implemented in Java 1.5. The syntax allows you to call a method with a comma separated list of arguments instead of an array.
public static void main(String... args);
main("this", "is", "multiple", "strings");
is the same as:
public static void main(String[] args);
main(new String[] {"this", "is", "multiple", "strings"});
http://today.java.net/article/2004/04/13/java-tech-using-variable-arguments
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
Check out the Java Language Specification, Third Edition, Chapter 8 (Classes). Buried in there is this nugget:
If the last formal parameter is a variable arity parameter of type T, it is considered to define a formal parameter of type T[]. The method is then a variable arity method. Otherwise, it is a fixed arity method. Invocations of a variable arity method may contain more actual argument expressions than formal parameters. All the actual argument expressions that do not correspond to the formal parameters preceding the variable arity parameter will be evaluated and the results stored into an array that will be passed to the method invocation (§15.12.4.2).
Basically, the last parameter of any method call can have T.... If it has that, it is converted to T[].
So basically, what you have is a fancy way of reproducing the more traditional
String[] args
It is varargs
In simple term its an Array of Member like
public setMembers(Member[] members);
When to use:
Generally while designing API it is good to use when number of argument is not fixed.
Example from standard API of this is String.format(String format,Object... args)
Also See
var-arg-of-object-arrays-vs-object-array-trying-to-understand-a-scjp-self-test
This is called variadic arguments, check here:
http://en.wikipedia.org/wiki/Variadic_function#Variadic_functions_in_C.23.2C_C.2B.2B.2FCLI.2C_VB.net.2C_and_Java
The official documentation (Java 1.5) is here:
http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
It's the so-called varargs syntax. In the method body, you can read the members parameter as it were an array - actually, it /is/ 'just' an array.
However, the magic bit is in calling the method. Before the varargs syntax was introduced, you'd call the method a bit like so:
setMembers(new Members[] {member1, member2, member3});
With the new varargs syntax however, you don't need to explicitly create the array anymore, and you can pass:
setMembers(member1, member2, member3);
This does mean however that a varargs argument has to be the last argument in a method. Something like this is therefore not permitted:
void setMembers(Member ... members, String memberType);
Summarized: It's a bit of syntactic sugar, really. I'm no expert on the inner workings of the Java compiler, but I'm pretty sure that methods calling a method that accept a varargs parameter are rebuilt into methods that build an array of the given type.
You might want to read up on Using Variable Arguments (or varargs) in Java.
It's called varadic argument: A function that takes as many (including zero) arguments as you want.
For example, main("string1", "string2", "string3") is same as main({"string1", "string2", "string3"}) if main is declared as void main(String...args).
See http://www.java-tips.org/blog/java-se/varargs-%E2%80%93-java-50-addition.html
It means you can pass zero or more Member objects to the setMembers() method. In the setMembers method, members will have array semantics.
Variable arguments. Can have 0 or more String arguments.
The function can access the parameters as an array of Strings.
It means that the method accepts a variable number of String arguments. The arguments are treated as an array and so are accessed by subscript, in the order they are passed in.