Sun's decision to jump from Java 1.4 to 5.0 in their
latest Java release caused some discussion within technical circles, not least because
it was launched with twin names of Java 1.4 and Java 5.0 dependant on which community was
using it. Sun explain their decision
here.
The
ServerSide people have
their
views
on it. Putting the versioning debate aside alongside the comprehensive improvements to many
of the Java libraries, Java 5.0 introduced radical changes to the Java programming langauge.
The key changes were:
- Generics - Avoid the dreaded cast when pulling objects from Collections
- Enhanced For Loop - Syntactic Sugar
- Autoboxing/Unboxing - Eliminates the need for int -> Integer, long -> Long, etc
- Typesafe Enums - Sophisticated C like enums
- Varargs - C like variable length function arguments
- Static Import - Use static members without qualifying by containing class
- Metadata - Add metadata to your classes
Generics
Generics are without doubt the most dramatic change to the Java programming language. In some
ways similar to C++ which has templates and C# which has a similar mechanism, Java classes
now appear to have an additional dimension. Generics appear most prominently in
Java Collection classes, typically used to avoid the use of casting when dealing with
collections of objects. Java programmers will probably be very familiar with the following
piece of code:
for(Iterator it = c.iterator(); it.hasNext(); ) {
MyObject mo = (MyObject)it.next();
}
The issue with the Java collections is that they must be capable of containing the most high level
of objects - the Object - to make them useful. Obviously this means that casts are required
when extracting objects from a collection related Class as can be seen in the code fragment
above. The key to generics is that an additional dimension of type is used, so for example
rather than declaring and defining an List as
List l = new ArrayList();
we now add an additional type parameter. The concept of the type parameter is central
to generics.
List<String> l = new ArrayList<String>();
Returning to the code fragment with the use of Iterator and casts, it is now safe
iterate through collections and avoid the cast.
List<String> l = new ArrayList<String>();
...
Add items to l
...
for(Iterator it = c.iterator(); it.hasNext(); ) {
MyObject mo = it.next();
}
Generics also present an extra level of type safety, if the programmer mistakenly
tried an incorrect cast a runtime error would occur. The compiler ensures the
assignment is correct at compile time.
The use of generics is not restricted
Enhanced for loop
The generics example which shows the use of the Iterator class is a coding cliche,
Java 5 has introduced a short cut (read syntactic sugar). We can now iterator through
a collection using this statement:
for(Collectoin col : var) {
var.invokeMethod();
}
Autoboxing/unboxing
The Java Collection classes can only contain references, primatives such as int and long
much be wrapped in their corresponding wrapper class (Integer, Long) and then 'unbox'
the method. Integer.intValue(). The following code sample illustrates this.
List al = new ArrayList();
al.add(12);
int g = al.get(0);
Variable arguments
Variable arguments have long been a feature of C, these can seen in action below.
public void varMethod(Object ... args) {
// args is now available as a local array
for(int i = 0; i < args.length; i++) {
}
}
Enums
An enum is a variable that contains an bounded integer value, which will be familiar
to C, C++ and C# rogrammers.
enum Type { CIRCLE, RECTANGLE, TRIANGLE }
Static imports
As a shortcut static imports now allow the import of static methods which would previously need to
be prefixed, the following code fragments demonstrates this in action.
import static java.lang.Math;
...
int m = min(45,678);
Metadata
Similar to attributes in C# which provide a facility to annotate code with metadata
Java 5 has annotations. In style they appear to be like Javadocs, although unlike Javadocs
it is possible to define new annotation types. A code example demonstrates these concepts.
It is important to remember the @Retention annotation which annotates the definition
of the Dev annotation, as by default the retention policy is compile time which means that
annotation detail cannot be derived via reflection (i.e. the reflection example below
will run silently as no annotations are found).
import java.util.*;
import java.lang.reflect.*;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@interface Dev {
String str();
}
public class GenericsTest {
public static void main(String args[]) {
Method ms[] = GenericsTest.class.getMethods();
for(int i = 0; i < ms.length; i++) {
if(ms[i].isAnnotationPresent(Dev.class)) {
Annotation ans[] = ms[i].getDeclaredAnnotations();
for(Annotation a : ans) {
System.out.println(a);
}
}
}
}
@Dev(str = "testing")
public void devMethod() {
}
}