Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 
Search the JavaFAQ.nu
1000 Java Tips ebook

1000 Java Tips - Click here for the high resolution copy!1000 Java Tips - Click here for the high resolution copy!

Java Screensaver, take it here

Free "1000 Java Tips" eBook is here! It is huge collection of big and small Java programming articles and tips. Please take your copy here.

Take your copy of free "Java Technology Screensaver"!.

Visiting your Collection's Elements

JavaFAQ Home » Story by Dr. Kabutz Go to all tips in Story by Dr. Kabutz


Bookmark and Share

The Java Specialists' Newsletter [Issue 040] - Visiting your Collection's Elements

Author: Dr. Heinz M. Kabutz

JDK version:

Category: Language

You can subscribe from our home page: http://www.javaspecialists.co.za (which also hosts all previous issues, available free of charge Smile

Welcome to the 40th edition of "The Java(tm) Specialists' Newsletter", sent to over 2550 Java experts in over 70 countries. Despite my plea that you don't unsubscribe, I had a rather surprising number of unsubscriptions, as programmers expressed their outrage at my audacity by voting with their feet. My views are my own and that of my employer - since I am my own employer Wink. I'm working on a program at the moment and I do make sure that our JavaDocs are up to date by running a Doclet that tells me where I've forgotten a tag. Whenever I change a method, I nuke the comments, and then the Doclet tells me where I need to add a comment again.

The ideas in this newsletter were spawned by Inigo Surguy (inigosurguy@hotmail.com) who works in Lemington Spa in the United Kingdom. Inigo is the UK Head of Research and Development of Interactive AG. Inigo also pointed out BCEL to me, used to change byte code "on the fly". I will write about some application of that in future.

A few newsletters ago, I mentioned traffic fines, and that I had had only one speeding fine in all my life. Last Wednesday, I was on my way to a meeting with my auditor, I was late, and, hmmm, make that 2 traffic fines in all my life? The road between where I live and where my auditor works is notorious. The police tell you: "if you have a puncture on that road, please carry on driving slowly until you get to the next town. Don't worry about damaging your wheel - rather break your wheel than ..." Ok, I'm exaggerating a bit, but the point I'm making is that I had never seen a speed trap on that road, because the cops are too scared to hang around long enough to book you. Never, until last Wednesday. I was caught fair & square, doing 160km/h in a 120km/h zone. Fortunately, the cop was in a good mood, so we had a good laugh when he pulled over some cops who were speeding, and he kindly reduced my speed to 139km/h. The speeding fine ended up being ZAR 100, about US$ 8.50. I'd be quite interested to hear from you what type of punishment you would face in your country for getting caught doing 160km/h in a 120km/h zone ... [hk: in case there are any cops on this list, that story was purely ficticious :-]


Mauritius - Paradise Island. Blue sands, crystal skies, white water. *yawn* - who wants beach anyway when you could be doing computer stuff? How about adding some *real* fun to the equation? How about having your cake and eating it too? How about a Design Patterns course at the colourful Coco Beach Hotel situated at Belle-Mare on the East coast of Mauritius? To find out more about this unique opportunity to spend your tax money on a holiday Wink, click on http://vik.cshons99.net/lifetimelearning. There are only a few places left, so please don't miss this unique opportunity.


Visiting your Collection's Elements

The Problem

I'm getting tired. Not tired of writing newsletters, but tired of Java. Tired of writing the same code over and over again. For example:

// ...
Iterator it = ages.iterator();
while(it.hasNext()) {
  Integer age = (Integer)it.next();
  System.out.println("Now you're " + age +
    ", in 3 years time, you'll be " + (age.intValue() + 3));
}

I don't like that while loop with the iterator. Don't know why I don't like it, it just looks inelegant to me. I like the weird for loop for an iterator even less:

// ...
for(Iterator it = ages.iterator(); it.hasNext()Wink {
  Integer age = (Integer)it.next();
  System.out.println("Now you're " + age +
    ", in 3 years time, you'll be " + (age.intValue() + 3));
}

Lastly, I don't like downcasting and I don't like the problems that occur when you have different types in a collection.

A different way ...

Before looking at a solution, I would like to show how I would use iterators normally:

import java.util.*;

public class OldVisitingIteratorTest {
  public static void main(String[] args) {
    Collection c = new LinkedList();
    for (int i=0; i<3; i++) c.add(new Integer(i));

    Iterator it = c.iterator();
    while(it.hasNext()) {
      // lots of brackets - looks almost like Lisp - argh
      System.out.println(((Integer)it.next()).intValue() + 10);
    }

    c.add(new Float(2.1));
    c.add("Hello");

    it = c.iterator();
    while(it.hasNext()) {
      Object o = it.next();
      if (o instanceof Integer) {
        System.out.println(((Integer)o).intValue() + 10);
      } else if (o instanceof Number) {
        System.out.println(((Number)o).intValue() + 20);
      } else if (o instanceof String) {
        System.out.println(((String)o).toLowerCase());
      } else {
        System.out.println(o);
      }
    }

    it = c.iterator();
    while(it.hasNext()) {
      System.out.println(((Integer)it.next()).intValue() + 10);
    }
  }
}

The output from that code is:

10
11
12
10
11
12
22
hello
10
11
12
Exception in thread "main" java.lang.ClassCastException: java.lang.Float
        at OldVisitingIteratorTest.main(OldVisitingIteratorTest.java:32)

Instead of constructing an Iterator and going through the Iterator and doing some operation on its contents, why not pass in an object with an execute() method that is called with each element? After some speed-typing yesterday, while waiting for my students at a Design Patterns course at the Strand Beach Hotel near Cape Town to finish an exercise, I came up with:

import java.util.*;
import java.lang.reflect.*;

public class VisitingIterator {
  /**
   * Ordering methods in "best-fit" order.
   */
  private static final Comparator METHOD_COMPARATOR =
    new Comparator() {
      public int compare(Object o1, Object o2) {
        Class paramType1 = ((Method)o1).getParameterTypes()[0];
        Class paramType2 = ((Method)o2).getParameterTypes()[0];
        return paramType1.isAssignableFrom(paramType2) ? 1 : -1;
      }
    };

  /**
   * Threadsafe version of visit.
   * @param lock the object on which to synchronize
   * @param task is an Object with an execute(...) : void method
   */
  public void visit(Collection c, Object task, Object lock) {
    synchronized(lock) {
      visit(c, task);
    }
  }

  /**
   * @param task is an Object with an execute(...) : void method
   */
  public void visit(Collection c, Object task) {
    TreeSet methods = new TreeSet(METHOD_COMPARATOR);
    Method[] ms = task.getClass().getMethods();
    for (int i=0; iif (ms[i].getName().equals("execute")
          && ms[i].getParameterTypes().length == 1) {
        methods.add(ms[i]);
      }
    }
    Iterator it = c.iterator();
    while(it.hasNext()) {
      boolean found = false;
      Object o = it.next();
      Iterator mit = methods.iterator();
      while(!found && mit.hasNext()) {
        Method m = (Method)mit.next();
        if (m.getParameterTypes()[0].isInstance(o)) {
            try {
              m.invoke(task, new Object[] { o });
            } catch(IllegalAccessException ex) {
              // we were only looking for public methods anyway
              throw new IllegalStateException();
            } catch(InvocationTargetException ex) {
              // The only exceptions we allow to be thrown from
              // execute are RuntimeException subclases
              throw (RuntimeException)ex.getTargetException();
            }
            found = true;
        }
      }
      if (!found)
        throw new IllegalArgumentException(
          "No handler found for object type " +
            o.getClass().getName());
    }
  }
}

Instead of having that ugly while loop, we can now pass an object to the VisitingIterator and the correct execute(...) method is called for each element in the collection. The OldVisitingIterator now becomes:

import java.util.*;

public class VisitingIteratorTest {
  public static void main(String[] args) {
    Collection c = new LinkedList();
    for (int i=0; i<3; i++) c.add(new Integer(i));
    VisitingIterator vit = new VisitingIterator();

    vit.visit(c, new Object() {
      public void execute(Integer i) {
        System.out.println(i.intValue() + 10);
      }
    });

    c.add(new Float(2.1));
    c.add("Hello");

    vit.visit(c, new Object() {
      public void execute(Object o) {
        System.out.println(o);
      }
      public void execute(Number n) {
        System.out.println(n.intValue() + 20);
      }
      public void execute(Integer i) {
        System.out.println(i.intValue() + 10);
      }
      public void execute(String s) {
        System.out.println(s.toLowerCase());
      }
    });

    vit.visit(c, new Object() {
      public void execute(Integer i) {
        System.out.println(i.intValue() + 10);
      }
    });
  }
}

The output from our new style is:

10
11
12
10
11
12
22
hello
10
11
12
Exception in thread "main" java.lang.IllegalArgumentException:
No handler found for object type java.lang.Float
        at VisitingIterator.visit(VisitingIterator.java:62)
        at VisitingIteratorTest.main(VisitingIteratorTest.java:33)

Perhaps I've been smoking Java for too long, but I much prefer that code to the while(it.hasNext()) ... but I have not had the chance to try this idea out "in the real world". I will start using it and let you know if it makes code neater (or not). I know that it will be less efficient, but then, Java is so slow anyway, I'd rather have cool style than super-optimal code.

Until next week ...

Heinz


Copyright 2000-2004 Maximum Solutions, South Africa

Reprint Rights. Copyright subsists in all the material included in this email, but you may freely share the entire email with anyone you feel may be interested, and you may reprint excerpts both online and offline provided that you acknowledge the source as follows: This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

Java and Sun are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Maximum Solutions is independent of Sun Microsystems, Inc.

 Printer Friendly Page  Printer Friendly Page
 Send to a Friend  Send to a Friend

.. Bookmark and Share

Search here again if you need more info!
Custom Search



Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy