Question

I have to use Java 1.4 and am using arraylist structures. Now I need to do some re-factoring and it would help if I can use Generics. Currently I have code like this

ArrayList rows = new ArrayList();

Which is a straightforward ArrayList. But now the "rows" variable is becoming more complex and need to define a "Row" class. I now want to do something like what you see in J2SE 1.5

ArrayList<Row> rows = new ArrayList();

A trawl through Google doesn't expose any answers without some sophisticated use of 3rd party solutions. How would my code have to change to accommodate this in 1.4, without using 3rd party solutions/open source projects, (if possible)?

Was it helpful?

Solution

Generics were introduced in JDK 1.5. So you can't use them in 1.4. However, you may be able to use JDK 1.5 compiler but target 1.4 with your classes with -target 1.4 javac option while keeping -source 1.5 option to indicate that your source is 1.5 compatible. In this case you can use generics as they should not affect result classes.

See the section on Cross-Compilation Options

OTHER TIPS

Generics tends to address the problem of what I deem "naive casts" in Java 1.4 or earlier when dealing with Collections. In Java 1.5+, the line you've placed:

ArrayList<Row> rows = new ArrayList();

would give a warning, the proper generic code is

ArrayList<Row> rows = new ArrayList<Row>();

This tells the compiler that your ArrayList object should only ever contain the Row type.

However, since Java 1.5 is backwards-compatible with huge sets of libraries that don't contain that syntax, but rather your previous code:

ArrayList rows = new ArrayList();

Generics obviously wouldn't work with these older libraries - therefore generics are only a compile time option - the 1.5 and 1.4 classes are effectively equivalent (minus any internal refactoring/new methods added later) because they are really ArrayList implementations that handle any Object type.

The 1.5 code simply adds in a direct cast for you.

In 1.4 code, say you wanted to iterate over the ArrayList. The naive cast way to do this is the following:

for(Iterator rowIterator = rows.iterator(); rowIterator.hasNext(); ) {
    Row row = (Row) rowIterator.next();
    // Do something with the row.
}

Java 1.5's code is exactly equivalent to the naive cast version. It takes the fact that you are telling the compiler that it is a row and does that code for you. So, the syntactic sugar benefits are nicer (this uses the newer for each loop syntax, but it generates the same code as the above loop):

for(Row row : rows) {
   // Do something with the row
}

So, if you want to use an ArrayList containing only rows, you still can. But there's no way to get the compiler to check that the ArrayList contains only all rows (although, even though the compiler provides this check, it is still possible to send in an ArrayList that contains other types of objects, since, again, the ArrayList still only really handles the Object type, and the generics are erased at runtime - all that remains is the naive cast code that you don't see anymore).

The non-naive variant is to check each instance and throw a ClassCastException yourself with an informative message (rather than have the program throw one with its default message):

for(Iterator rowIterator = rows.iterator(); rowIterator.hasNext(); ) {
    Object shouldBeRow = rowIterator.next();
    if(!(shouldBeRow instanceof Row)) {
        throw new ClassCastException("The object " + shouldBeRow + " is not an instance of Row - only Rows should be present in the list!");
    }
    Row row = (Row) shouldBeRow;
    // Do something with the row.
}

However, generally no one does this - good documentation can make this issue moot, as it places the burden of providing the correct collection on the caller and thus you can just have the ClassCastException thrown by the JVM.

Yes you can. Use a 1.5 compiler, and use

javac -target jsr14 ............

This will generate java 1.4 classes, but allow generics.

This switch can only be used for non byte code visible 1.5 features. For instance you can't use Enums, or new methods introduced in 1.5. But generics are fine, as they are not really present in the byte code.

No, you can't use them in JDK 1.4. They were introduced in JDK1.5

All you have to do is cast them. This could merit a runtime exception if you put "wrong" types into the list.

Row arow = (Row) rows.get(0);

for ($i=0; i<rows.size(); $i++){
    Row element = (Row) rows.get($i);
    element.printCells();
    (...)
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top