|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
AbstractJava 5 has some nice features. In this article, we will discuss these features, and see how you can benefit from these. In Part-I we cover auto-boxing and Java 5 FeaturesA number of interesting features have been added to the Java language in the 1.5 version, or Java 5 as it is referred to. The language level features are auto-boxing, Most of these features can be considered a progress. These improve the productivity of developers in cutting down verbose syntax and making code more intuitive. The following figure shows my opinion on the usefulness of the features:
The features on the left ( Auto-boxingJava has two classes of citizens: objects and primitives. You can’t really mix them well in your code. What if you want to write a generalized API that can accept any parameter type. This is done in the Reflection API. Let’s write a poor imitation of Reflection’s package com.agiledeveloper;
class A {}
class B {}
public class Test
{
public static void foo1(A obj)
{
System.out.println("foo called with " + obj);
}
public static void foo2(A obj1, B obj2)
{
System.out.println("foo2 called with " + obj1 + " and " + obj2);
}
// Poor imitation of refelction API to illustrate the point
public static void invoke(String method, Object[] args)
{
if (method.equals("foo1"))
{
foo1((A) args[0]);
}
if (method.equals("foo2"))
{
foo2((A) args[0], (B) args[1]);
}
}
public static void main(String[] args)
{
invoke("foo1", new Object[]{new A()});
invoke("foo2", new Object[]{new A(), new B()});
}
}
In public static void foo3(int value)
{
System.out.println("foo3 called witih " + value);
}
How do we call this method using the This approach of manual boxing and manual unboxing has quite a few disadvantages:
Let’s modify the public static void invoke(String method, Object[] args)
{
if (method.equals("foo1"))
{
foo1((A) args[0]);
}
if (method.equals("foo2"))
{
foo2((A) args[0], (B) args[1]);
}
if (method.equals("foo3"))
{
foo3(((Integer) (args[0])).intValue());
}
}
And, the call to it will look like: invoke("foo3", new Object[]{new Integer(3)}); // Until Java 1.4
Notice how you place (or box) the value 3 into the In Java 5, the auto-boxing and auto-unboxing feature is intended to alleviate this clutter. While this is still happening under the hood, at the source code level, we don’t have to do this. Here is the modified code: invoke("foo3", new Object[] {3});
The above code, when compiled, is translated so that the value of 3 is boxed into an Let’s consider another example – we will add a method public static Integer foo4(Integer v)
{
System.out.println("foo4 called with " + v.intValue());
return new Integer(5);
}
Now, here is a way to call this using the Java 5 auto-boxing/unboxing feature: int someValue = foo4(4);
System.out.println("Result of call to foo4 " + someValue);
As you can see, this code looks more natural and has less clutter. Pros and Cons:
92: iconst_4
93: invokestatic #31;
//Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
96: invokestatic #33;
//Method foo4:(Ljava/lang/Integer;)Ljava/lang/Integer;
99: invokevirtual #23;
//Method java/lang/Integer.intValue:()I
102: istore_1
This source code presents an appearance that is deceiving. It has performance consequences, especially if you are invoking methods with intense computational needs. Integer object is null, assigning it to int will result in a runtime exception – NullPointerException – being thrown.== means. For objects, you are comparing identity, for primitive types, you are comparing value. In the case of auto-unboxing, the value based comparison happens.foreachLooping is a control structure that has been around ever since we started programming. The good old syntax for looping that you would have used most often is: for(int i = 0; i < arr.length; i++)
{
... = arr[i] ...
}
While this structure is simple, we are forced to use the index What if you want to iterate over a collection, like for(Iterator iter = lst.iterator(); iter.hasNext(); )
{
System.out.println(iter.next());
}
Not very elegant, is it? In the The package com.agiledeveloper;
import java.util.ArrayList;
import java.util.Iterator;
public class Test
{
public static void main(String[] args)
{
String[] messages = {"Hello", "Greetings", "Thanks"};
for (int i = 0; i < messages.length; i++)
{
System.out.println(messages[i]);
}
for (String msg : messages)
{
System.out.println(msg);
}
ArrayList lst = new ArrayList();
lst.add(1);
lst.add(4.1);
lst.add("test");
for (Iterator iter = lst.iterator(); iter.hasNext();)
{
System.out.println(iter.next());
}
for (Object o : lst)
{
System.out.println(o);
}
ArrayList<Integer> values = new ArrayList<Integer>();
values.add(1);
values.add(2);
int total = 0;
for (int val : values)
{
total += val;
}
System.out.println("Total : " + total);
}
}
The for (String msg : messages)
as “foreach String msg in messages”. Instead of inventing another keyword “foreach”, the designers decided to use the good old “for”. Also, “in” may be used in existing code for fields, variables, or methods. In order to avoid stepping over your toes, they decided to use the As you can see, the looping is much simpler, more elegant (ignoring the ugly The code: for (String msg : messages)
{
System.out.println(msg);
}
translates to: 51: aload_1
52: astore_2
53: aload_2
54: arraylength
55: istore_3
56: iconst_0
57: istore 4
59: iload 4
61: iload_3
62: if_icmpge 85
65: aload_2
66: iload 4
68: aaload
69: astore 5
71: getstatic #6;
//Field java/lang/System.out:Ljava/io/PrintStream;
74: aload 5
76: invokevirtual #7;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V
79: iinc 4, 1
82: goto 59
For the array, for (Object o : lst)
{
System.out.println(o);
}
where 157: aload_2
158: invokevirtual #22;
//Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
161: astore_3
162: aload_3
163: invokeinterface #18, 1;
//InterfaceMethod java/util/Iterator.hasNext:()Z
168: ifeq 190
171: aload_3
172: invokeinterface #19, 1;
//InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
177: astore 4
179: getstatic #6; //Field java/lang/System.out:Ljava/io/PrintStream;
182: aload 4
184: invokevirtual #20;
//Method java/io/PrintStream.println:(Ljava/lang/Object;)V
187: goto 162
As you can see, in this case, the So, In the above example, I have used /** Implementing this interface allows an object to be the target of
* the "foreach" statement.
*/
public interface Iterable<T> {
/**
* Returns an iterator over a set of elements of type T.
*
* @return an Iterator.
*/
Iterator<T> iterator();
}
Let’s give this a try: //Wheel.java
package com.agiledeveloper;
public class Wheel
{
}
//Car.java
package com.agiledeveloper;
import java.util.Iterator;
import java.util.ArrayList;
public class Car implements Iterable<Wheel>
{
ArrayList<Wheel> wheels = new ArrayList<Wheel>();
public Car()
{
for(int i = 0; i < 4; i++)
{
wheels.add(new Wheel());
}
}
public Iterator<Wheel> iterator()
{
return wheels.iterator();
}
}
Now, I can use the Car aCar = new Car();
for(Wheel aWheel : aCar)
{
// aWheel ...
}
Pros and Cons:
ConclusionJava 5 has some nice features. In Part I, we discussed two of these: auto-boxing and References
|
|||||||||||||||||||||||||||||||||||