This is compiling fine :-
public class Demo {
public static void main(String... args) {
}
}
But this is not getting compiled.
public class Demo {
public static void main(String... args) {
String... strVarArgs ;
//here i initiallize strVarArgs by some logic, like we do for arrays
}
}
Plz correct me, if i am syntactically wrong. :-)
cletus wrote :-
It's really just syntactic sugar for an array
Here is an example followed by a statement from a very popular java book written by
Kathy Sierra and Bert Bates (Head First Java, 2nd Edition, McGraw-Hill/Osborne) :-
Topic generics,
<T extends MyClass>, where MyClass is a class, and
<T extends MyInterface>, where MyInterface is an interface.
Following is the as it is copy from book (page 548, chapter 16) :-
In generics, "extends means" "extends or implements"???
The java engineers had to give you a way to put a constraint on a parameterized type, so that you can restrict it to. But you also need to constrain a type to allow only classes that implement a particular interface. So, here's a situation where we need one kind of syntax to work for both situations-inheritence and implementation. In other words, that works for both extends and implementations. And the winning word was ...extends.
Whenever there's a chance for the sun engineer's to reuse an existing keyword, as they did here with "extends", they will usually do that. But sometimes they don't have a choice...(assert, enum).
MyQuestion : Is var-args just a syntactic sugar of array, with no other features then array???
Yes, varargs only applies to function arguments.
It's really just syntactic sugar for an array so instead of:
String... strVarArgs ;
you want
String strVarArgs[];
Example:
public class VargArgsExample {
public static void printArgs(long requiredLongArgument, String... notRequiredStringArray) {
System.out.println(requiredLongArgument);
if (notRequiredStringArray != null) {
for(String arg: notRequiredStringArray) {
System.out.println(arg);
}
}
}
public static void main(String[] args) {
printArgs(1L);
printArgs(1L, "aa");
printArgs(1L, "aa", "bb");
}
}
As you can see this syntax sugar allows us to call methods without specifing varargs argument. If no vararg argument is passed than it is null.
There is no need in just another way of variable declaration, so it is not used for it. And that is why you're getting compile-time error.
Related
I'm a beginner in Java, and while I was exploring I got to see a code which has the usage as Fruit... fruitName? I have ever seen such a usage in any documentation like ...
Can anyone know what and how the usage of this?
No, a class name in Java cannot contain the . character.
The ... syntax is a way of declaring a method that receives any number of arguments from a given type (and treats them internally as an array.
E.g.:
public void printAllFruits (Fruit... fruits) {
// fruits is a Fruit[]:
for (Fruit fruit : fruits) {
System.out.println(fruit);
}
}
public static void main(String[] args) {
Fruit f1 = new Fruit("apple");
Fruit f2 = new Fruit("pear");
Fruit f3 = new Fruit("banana");
// This would work:
printAllFruits(f1);
// And so will this:
printAllFruits(f1, f2, f3);
}
valid characters in a java class name
... is used in Java also. It's called variable argument. It is used when you want to get some arguments which have same type, but the number of arguments is not sure. It's also used in C. Think about scanf/printf function.
class Fruit {
// Class implementation
}
public void extractJuice(Fruit... args) {
// This method can take variable arguments of type Fruit
}
So what you are looking at is varargs short for Variable Arguments.
Futher references:
- When do you use varargs in Java?
The only things you can have in a class name in Java are alphabetical letters of any case, numbers (although you can't start a class name with a number) and underscores.
The only case that an ellipsis (...) can follow a class name is when you're specifying a variable argument list of that class.
Consider the function foo, defined
void foo(Fruit... fruits){
for (fruit : fruits){
/*each argument considered here*/
}
}
foo could then be called with any number of Fruit instances.
So, good ol' Dietel states, "All generic method declarations have a type-parameter section delimited by angle brackets (< and >) that precedes the methods return type," (Deitel, 2012, italicized emphasis mine). The example given is as follows:
public static < T > void printArray (T[] inputArray)
{
for (T element : inputArray)
(
System.out.printlf("%s", element);
}
That makes sense to me. I get that. But, here is my question, not addressed explicitly in the book.
I have a very simple class to demonstrate:
public class Pair<F, S>
{
private F first;
private S second;
}
Now, according to Deitel, "ALL" generic method declarations must contain a type-parameter section. So, naturally, I want to add a get() and set() method to my class example. So, I do this:
public class Pair<F, S>
{
private F first;
private S second;
// Here, I'll do one instead of both for the sake of shortening the code
public < F > F getF()
{
return F;
}
// And the Accessor:
public < F > void setF(F first)
{
this.first = first;
}
}
So, here's the deal. The Eclipse IDE gives me a warning ahead of my attempt to compile (the Java version of Intellisense) that states, "The type parameter F is hiding the type F". Now, I don't particularly trust Dietel for Java - and am growing to understand that they are not particularly reliable (in that they often leave out important distinctions). So, I went to the Oracle Documentation for what I am doing and - GUESS WHAT - they mention nothing of the sort, unless you're talking about 'upperbounded' type parameters.
Here's the question (it's threefold):
Is the difference here the `static' qualifier, i.e. that the method I am writing appears in a class?
What on Earth is Dietel doing, particularly as implementation of their suggestions, here, yields a warning?
By changing the class type parameters, I get rid of the warning. So, conceptually, what is going on to where the method parameter type is "hiding" the class parameter type?
The JLS specifically designates a generic method as one that declares type parameters. (JLS) So the confusion here is that Deital has said that "all generic methods have a type parameter section" but presumably not specifically pointed out that this is their definition. It is more clear to say that "a generic method is one that has a type parameter section".
As noted in a comment, when you have type parameters declared by a class, you do not need to redeclare them at the method. As noted by Eclipse, doing so actually declares new type parameters which hide the ones declared by the class.
When they are declared on the class you can use them directly:
class Pair<F, S> {
F getF() { ... }
S getS() { ... }
void setF(F f) { ... }
void setS(S s) { ... }
}
The purpose of a generic method is to use it parametrically. The given example is not particularly good for understanding because the generic type is actually unused: the printf overload for Object is called. It can be rewritten without generics with no change to its functionality:
public static void printArray(Object[] arr) {
for(Object o : arr) {
System.out.printf("%s", o);
}
}
The easiest example for understanding the use of a generic method is the implementation of Objects#requireNonNull which is something like this:
public static <T> T requireNonNull(T obj) {
if(obj == null)
throw new NullPointerException();
return obj;
}
It takes any object and conveniently returns it as a T:
// T is inferred
String hello = Objects.requireNonNull("hello world");
// T is provided as a witness (rarely necessary)
Integer five = Objects.<Integer>requireNonNull(5);
It is the simplest generic method.
There seems to be a bug in the Java varargs implementation. Java can't distinguish the appropriate type when a method is overloaded with different types of vararg parameters.
It gives me an error The method ... is ambiguous for the type ...
Consider the following code:
public class Test
{
public static void main(String[] args) throws Throwable
{
doit(new int[]{1, 2}); // <- no problem
doit(new double[]{1.2, 2.2}); // <- no problem
doit(1.2f, 2.2f); // <- no problem
doit(1.2d, 2.2d); // <- no problem
doit(1, 2); // <- The method doit(double[]) is ambiguous for the type Test
}
public static void doit(double... ds)
{
System.out.println("doubles");
}
public static void doit(int... is)
{
System.out.println("ints");
}
}
the docs say: "Generally speaking, you should not overload a varargs method, or it will be difficult for programmers to figure out which overloading gets called."
however they don't mention this error, and it's not the programmers that are finding it difficult, it's the compiler.
thoughts?
EDIT - Compiler: Sun jdk 1.6.0 u18
The problem is that it is ambiguous.
doIt(1, 2);
could be a call to doIt(int ...), or doIt(double ...). In the latter case, the integer literals will be promoted to double values.
I'm pretty sure that the Java spec says that this is an ambiguous construct, and the compiler is just following the rules laid down by the spec. (I'd have to research this further to be sure.)
EDIT - the relevant part of the JLS is "15.12.2.5 Choosing the Most Specific Method", but it is making my head hurt.
I think that the reasoning would be that void doIt(int[]) is not more specific (or vice versa) than void doIt(double[]) because int[] is not a subtype of double[] (and vice versa). Since the two overloads are equally specific, the call is ambiguous.
By contrast, void doItAgain(int) is more specific than void doItAgain(double) because int is a subtype of double according the the JLS. Hence, a call to doItAgain(42) is not ambiguous.
EDIT 2 - #finnw is right, it is a bug. Consider this part of 15.12.2.5 (edited to remove non-applicable cases):
One variable arity member method named m is more specific than another variable arity member method of the same name if:
One member method has n parameters and the other has k parameters, where n ≥ k. The types of the parameters of the first member method are T1, . . . , Tn-1 , Tn[], the types of the parameters of the other method are U1, . . . , Uk-1, Uk[]. Let Si = Ui, 1<=i<=k. Then:
for all j from 1 to k-1, Tj <: Sj, and,
for all j from k to n, Tj <: Sk
Apply this to the case where n = k = 1, and we see that doIt(int[]) is more specific than doIt(double[]).
In fact, there is a bug report for this and Sun acknowledges that it is indeed a bug, though they have prioritized it as "very low". The bug is now marked as Fixed in Java 7 (b123).
There is a discussion about this over at the Sun Forums.
No real resolution there, just resignation.
Varargs (and auto-boxing, which also leads to hard-to-follow behaviour, especially in combination with varargs) have been bolted on later in Java's life, and this is one area where it shows. So it is more a bug in the spec, than in the compiler.
At least, it makes for good(?) SCJP trick questions.
Interesting. Fortunately, there are a couple different ways to avoid this problem:
You can use the wrapper types instead in the method signatures:
public static void doit(Double... ds) {
for(Double currD : ds) {
System.out.println(currD);
}
}
public static void doit(Integer... is) {
for(Integer currI : is) {
System.out.println(currI);
}
}
Or, you can use generics:
public static <T> void doit(T... ts) {
for(T currT : ts) {
System.out.println(currT);
}
}
class Test{
public static void main(String... s){
System.out.println("Hello");
}
}
class Test{
public static void main(String[] s){
System.out.println("Hello");
}
}
What is the difference between above two syntax of main() declaration?
Does Java has any special need to have variable length argument?
No difference (when you run the program from the command line, i.e. what the main method is used for). The first variant appeared after Java 5 introduced varargs.
In short, varargs allows you to pass a variable number of arguments to a method. For the method body the arguments are grouped into an array. Like Test.main("foo", "bar") instead of Test.main(new String[] {"foo", "bar"}). The compiler does the array creation for you behind the scene.
The only difference is if you call main directly from other Java code. The first form allows you to write:
Test.main("first", "second", "third");
whereas the second would require you to create an array explicitly:
Test.main(new String[] { "first", "second", "third" });
Personally I don't think I've ever seen the first form used - calling main from other code is pretty rare. There's nothing wrong with it though.
There is no difference.
In general, String... s allows to pass arguments with comma as separator, while the String[] s requires an array.
But in the implementation s is array in both cases. So ... is sintactic sugar in a sense.
Variable number of arguments main(String... s) was only introduced in Java 5.0.
This is the follow up of my question here: Weird Java generic.
If I have a code like this:
Casts.<X, T> cast(iterable[index]);
Can I add a static import and do:
<X, T> cast(iterable[index]);
Eclipse doesn't allow this. But after seeing so many bugs with static import in Eclipse, I'm not that certain.
No, you can't : I just confirmed this via some test code.
PS > javac -version
javac 1.6.0_04
Casts.java
public class Casts
{
public static <From, To> To cast(final From object)
{
return (To)object;
}
}
Test.java
import static Casts.cast;
public class Test
{
public static void main(String[] args)
{
final Integer integer = new Integer(5);
// This one compiles fine.
final Number number = Casts.<Integer, Number>cast(integer);
// This one fails compilation:
// PS> javac Test.java
// Test.java:11: illegal start of expression
// final Number number = <Integer, Number>cast(integer);
// ^
// Test.java:11: not a statement
// final Number number = <Integer, Number>cast(integer);
// ^
final String string = <Integer, String>cast(integer);
}
}
No
If you want to provide an explicit type parameter when calling a generic static method, you must prefix the method with the class name, even if the method is statically imported.
Java grammar allows type arguments only with typename specified. See corresponding section in JLS https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-MethodInvocation
I'm pretty sure the answer is no--if you want to use a generic method call, you need an object to call it on (foo.<T>doSomething()). If the method is static, you need the class ( Foo.<T>doSomething() ).
This is even true if you're calling the method from elsewhere in the class itself. If you are working in a non-static method (i.e. in an instance method), you would call this.<T>doSomething().
As far as I've read, a shortcoming of the static import mechanism is that you must specify the calling object/class if you wish to provide formal parameters. In this example, it's not very clear why there are two generic parameters, but if you wish to avoid having to specify the calling object/class you can type hint through a cast of the arguments as such:
public static <E> E foo(E e) {}
Number n = foo((Number)3);
With the type hint, the type inference will return an object of type Number, instead of Integer as it would have reasoned otherwise.