|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
AbstractIn Part I, we discussed the Java 5 features of auto-boxing and VarargsAssume you want to invoke a method with a variable number of arguments. The option we had on hand in Java 1.4 or earlier was to pass an array. Let’s consider a simple example as shown below: public static int max(int[] values)
{
int max = values[0];
for(int aValue : values)
{
if (aValue > max) max = aValue;
}
return max;
}
We can invoke this method by passing an array with different number of values, as illustrated below: max(new int[] {1, 7, 2, 9, 8});
max(new int[]{8, 12, 87, 23, 1, 3, 6, 9, 37});
In order to invoke a method that takes variable number of arguments, we had to bundle the parameters into an array. While this works, it is not elegant. The varargs introduced in Java 5 addresses the elegance issue. Before we look at that, let’s talk about how C++ handled this. In C++, you could pass a variable number of arguments to methods by using the concept of ellipsis (…). While that is an interesting concept, it has two significant problems. First, the code to get different parameters within the method is not simple. You have to use a special set of functions ( The varargs concept in Java 5 does not suffer from these issues. It is not only elegant, but also is very type safe. Let’s take the public static int max(int... values)
Notice that the only thing I changed is A type followed by … is simply a syntax sugar – it’s nothing but an array. However, the compiler allows you to pass either an array or a discrete set of values to this method. For example, now I can call the modified max(new int[] {1, 7, 2, 9, 8});
max(new int[]{8, 12, 87, 23, 1, 3, 6, 9, 37});
max(1, 7, 2, 9, 8);
max(8, 12, 87, 23, 1, 3, 6, 9, 37);
There’s less clutter in the bottom two lines than in the top two lines. But what’s going on when you pass discrete values? The compiler simply rolls the values into an array. So, the code: max(1, 7);
is compiled into: max(new int[] {1, 7});
as you can see from the following byte code: 0: iconst_2
1: newarray int
3: dup
4: iconst_0
5: iconst_1
6: iastore
7: dup
8: iconst_1
9: bipush 7
11: iastore
12: invokestatic #2; //Method max:([I)I
In the above example, we passed an array of public static void print(Object... values)
{
for(Object obj : values)
{
System.out.printf("%s is of type %s\n", obj, obj.getClass().getName());
}
}
The above code receives a varargs of type print(1, "test", 'a', 2.1);
The output from this call is: 1 is of type java.lang.Integer
test is of type java.lang.String
a is of type java.lang.Character
2.1 is of type java.lang.Double
The first line should be no surprise if you kept auto-boxing in mind–that is the reason for the type to be You are not restricted to having only varargs as parameters; that is, you can have regular parameters and varargs, if you like. However, varargs, if present, must be trailing. In other words, place any regular parameter you like, and then place the varargs as shown in the following example: public static void print(String msg, Object... values)
Pros and Cons:
Static importsAn import statement allows you to give a hint to the compiler as to which class you are referring to in your code. It gives you the convenience of using the short name for a class (like Of course, if classes in multiple package/namespace collide, then we will get an error. In this case, you can resort to using the fully qualified name for the class. While import gives you convenience, it does have a disadvantage. It does not clearly indicate to the reader as to where the class being used comes from. If you have several imports at the top of your code, then it may take a while for a reader of your code to figure out which classes belong to which package/namespace. Static import is a concept in Java 5 that unfortunately aggravates this. Let’s take a look at the following code: package com.agiledeveloper.com;
public class Test
{
public static void main(String[] args)
{
System.out.println("Math.abs(-2) = " + Math.abs(-2));
System.out.println("Math.ceil(3.9) = " + Math.ceil(3.9));
}
}
Looking at this code, you can quickly figure out that I am calling the methods package com.agiledeveloper.com;
import static java.lang.Math.abs;
import static java.lang.Math.ceil;
import static java.lang.Runtime.*;
public class Test
{
public static void main(String[] args)
{
System.out.println("Math.abs(-2) = " + abs(-2));
System.out.println("Math.ceil(3.9) = " + ceil(3.9));
System.out.printf("Free memory is = %d", getRuntime().freeMemory());
}
}
In the above code, we are making a call to Baring the issue of difficulty to identify where methods have come from, static import has some advantages. For instance, in EasyMock 2.0, static import is used to reduce the verbosity of the code. In using the mock, you would write code like: SomeInterface mock = (SomeInterface) createMock(SomeInterface.class);
expectCall(mock.foo()).andReturn(5);
replay(mock);
…
The underlined methods above are all part of the import static org.easymock.EasyMock.*;
Pros and cons:
Enum, annotation, and genericsThe concepts of enum, annotation, and generics deserve their own coverage. Enum is pretty interesting in Java 5, and it is a realization of Jashua Bloch’s recommendations for writing enum well. Other featuresIn this article, we have focused on the language features in Java 5. Java 5 has some other interesting features as well. Listed below are some select features:
ConclusionIn this Part-II of the Java 5 features article, we discussed the benefits of varargs, and saw how it can make our code elegant and easier to use. It is simply a syntax sugar where you can pass an array or discrete values to a method. We also looked at the static imports, which we recommend that you use sparingly. References
|
||||||||||||||||||||||||||||||||||||||||||||