java.util.Properties and Generics

12 AM July 10, 2006

I can’t wait for Java 6.0. It looks like community involvement is a success.

For instance, just now, I was working in JDK1.5, where I had a properties file and needed to see the kes. I wrote:


  for (String key : props.keySet()) { 
        ...
  }

Which seems sensible enough, except that the compiler rejects it with, “Type mismatch: cannot convert from element type Object to String”. A little bit of digging found the JDK1.5 Properties class declaration:


   public
   class Properties extends Hashtable<Object,Object> {
       ....

Given that the Javadoc says, “Each key and its corresponding value in the property list is a string”, I can’t see why Properties doesn’t extend Hashtable<String, String>. Looks like laziness to me, but if someone has an alternate explanation, I’d appreciate hearing it.

On the bright side, it seems that I’m not the first person to encounter the issue, and, according to this bug report, Java 6.0 will have a way to do what I want without casting. Hoorah!

Update: This is the pre-Java 6.0 workaround:


  for (String key : (Set<String>) (Set) props.keySet()) {
        ...
  }

Oh, and don’t forget to add @SuppressWarnings(“unchecked”) to the method declaration.

By alang | # | Comments (2)
(Posted to javablogs, Java and Rants)

Comments

At 00:56, 10 Jul 2006 Bill Mill wrote:

Thanks for reminding me why I don't like Java!

(#)
At 11:59, 10 Jul 2006 Ricky Clarkson wrote:

A somewhat better way of doing that would probably be to use Object's toString.

Here's the end result, first:

for (String key: asStrings(props.keySet()))
        whatever;

And now the bit of code you don't look at often that makes the above possible:

Iterable<String> asStrings(final Iterable<Object> objectIterable)
{
        return new Iterable<String>()
        {
                public Iterator<String> iterator()
                {
                        final Iterator<Object> objectIterator=objectIterable.iterator();
        
                        return new Iterator<String>()
                        {
                                public boolean hasNext()
                                {
                                        return objectIterator.hasNext();
                                }
        
                                public String next()
                                {
                                        return objectIterator.next().toString();
                                }
        
                                public void remove()
                                {
                                        objectIterator.remove();
                                }
                        };
                }
        };
}

Yes, it's big, yes it's clunky, but it's somewhere you don't have to look at often. Easy to test, and no, I didn't test it. The runtime cost would be negligible, and it would be safe in the case of an implementation of Properties not using Strings as keys.

You could generify this for conversions between any other two types if you liked too.

I won't write this in full now (ask me if you want me to), but you could have something like:

 <A,B> Iterable<B> convert(Iterable<A>,Converter<A,B> converter);

It's a shame that Sun did not change the existing method, if it is actually a mistake, as changing it would not affect anybody's runtime (thanks to erasure), only their compilation, and it would be an easy fix for client code. However, the bug report doesn't seem to conclude that this is actually a mistake.

I'd like to see Sun fix more mistakes, rather than add new API over the top of old, especially when they don't deprecate the old.

(#)

Add Comment




(Not displayed)






(Leave blank line between paragraphs. URLs converted to links. HTML stripped. Indented source code will be formatted with <pre> tags.)




© 2003-2006 Alan Green