|
The Java Specialists' Newsletter
Issue 107 2005-04-19
Category:
Language
Java version: Sun JDK 1.5.0_02 Making Enumerations Iterableby Dr. Heinz M. Kabutz
Welcome to the 107th edition of The Java(tm) Specialists' Newsletter, sent to you from
Vienna, Austria. Vienna is a beautiful city with lots of
old buildings and culture. Thanks to Thomas Eichberger from
AGILA Softwareentwicklung
und Schulung for showing me around Vienna.
A special treat was meeting up with family Mahrl, who I last
saw in Cape Town over 20 years ago. Franz Mahrl was probably
the first real computer programmer that I met, and may have
been an inspiration to eventually pursue the career. I
certainly do not regret becoming a programmer. We have the
best jobs in the world - and we even get paid for having fun!
It is great to meet up with the heros of your childhood, and
try to peer through the dark curtains of time.
Next week I will be in Siegen, Germany, so please let me know
if you would like to pop over for a coffee and a chat about
Java, South Africa, the world, etc., one of the evenings.
Thanks for reading this newsletter on our website. We also have a mailing list. That is where the real action takes place (webinars, free reports, etc.). Maybe subscribe today?
Advanced Java Courses on Crete:Java Specialists Master Course 18-21 June 2013 and
Concurrency Specialists Course 6-9 August 2013.
Making Enumerations Iterable
There are some parts of Java where we still see Enumeration
being used. I performed a search with IntelliJ and was
amazed how often it still occurs. Changing the interface of
existing classes is not always feasible, so we sometimes need
to iterate through an Enumeration. For an example, look at
newsletter
#106 where we enumerate through the columns.
Unfortunately, we then cannot use the nice for/in construct
to iterate through the enumeration - or can we?
It is possible to get an Enumeration over a Collection by
calling the function java.util.Collections.enumeration(Collection). That does
not help us though, since it is going in the wrong direction.
We want to iterate through an Enumeration.
We could also convert the Enumeration to an ArrayList
using the method java.util.Collections.list(Enumeration)
and then use that as the expression in the for/in construct.
This is also not ideal though, since we then have to
construct an ArrayList each time we want to iterate. This
can be expensive, especially with a large Collection.
I therefore propose to rather build an adapter for the
Enumeration, and then make an IterableEnumeration that
satisfies the Iterable interface, and is Generics enabled:
import java.util.*;
public class IterableEnumeration<T> implements Iterable<T> {
private final Enumeration<T> en;
public IterableEnumeration(Enumeration<T> en) {
this.en = en;
}
// return an adaptor for the Enumeration
public Iterator<T> iterator() {
return new Iterator<T>() {
public boolean hasNext() {
return en.hasMoreElements();
}
public T next() {
return en.nextElement();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public static <T> Iterable<T> make(Enumeration<T> en) {
return new IterableEnumeration<T>(en);
}
}
Ignore the static make function for now. We
can use it by constructing an instance of IterableEnumeration
giving it the generic type, like so:
import java.sql.*;
import java.util.*;
public class IterableTest {
public static void main(String[] args) {
Vector<String> sv = new Vector<String>();
sv.addElement("Maximilian");
sv.addElement("Francis");
sv.addElement("Kabutz");
// using the generics makes it look a bit clumsy
IterableEnumeration<String> ie =
new IterableEnumeration<String>(sv.elements());
for (String s : ie) {
System.out.println(s);
}
// Without generics, we cannot automatically cast to String
IterableEnumeration ie2 =
new IterableEnumeration(sv.elements());
for (Object s : ie2) { // here we now have to use Object type
System.out.println(s);
}
// Again, generics makes the code look clumsy
// here you should load your own driver, if applicable
new sun.jdbc.odbc.JdbcOdbcDriver();
IterableEnumeration<Driver> drivers =
new IterableEnumeration<Driver>(
DriverManager.getDrivers());
for (Driver driver : drivers) {
System.out.println("driver = " + driver.getClass());
}
// or we could build up the list using Collections.list()
// and iterate through that - this is ineffient.
for (Driver driver : Collections.list(
DriverManager.getDrivers())) {
System.out.println("driver = " + driver.getClass());
}
}
}
If possible, I want to use the compile-time checking of
generics without having to see the ugly syntax. That is why
I wrote the make method, which returns the
correct type without me having to specify it anywhere:
import java.sql.*;
import java.util.Vector;
public class IterableTestStatic {
public static void main(String[] args) {
Vector<String> sv = new Vector<String>();
sv.addElement("Maximilian");
sv.addElement("Francis");
sv.addElement("Kabutz");
// Use a static "factory method" to reduces generics clutter
for (String s : IterableEnumeration.make(sv.elements())) {
System.out.println(s);
}
// This also looks slightly more readable
new sun.jdbc.odbc.JdbcOdbcDriver();
for (Driver driver : IterableEnumeration.make(
DriverManager.getDrivers())) {
System.out.println("driver = " + driver.getClass());
}
}
}
I personally find that more readable. It seems to me, though
this is just an observation, that static methods are slightly
more powerful when it comes to generics.
Kind regards
Heinz
Language Articles
Related Java Course
Discuss at The Java Specialist Club
|