jump to navigation

Elementary Java Solutions August 8, 2007

Posted by WarpedJavaGuy in java, programming.
trackback

The sooner we start coding fewer frameworks and more programs the sooner we’ll become better programmers.
 

The Java community has solved many programming problems and developed many reusable libraries. The number of Java projects, frameworks, and libraries that exist today is overwhelming. It has become standard practice for Java programmers to utilise these libraries in their everyday programming lives. Java programmers take advantage of the fact that for almost every Java problem there almost certainly exists at least one readily available and published online solution that can easily be copied or downloaded. They believe in maximising code reuse and spending less time solving problems and more time developing code. It is no surprise that the Java programmers of today have mastered the art of OO reusability. They are extremely efficient at reusing existing class libraries and are increasingly efficient at creating new ones too.

I recently found a great article at Chaotic Java on coding iterators that introduced a solution for iterating over varying types of object collections and only returning those that satisfy certain given conditions or predicates. I’m a big fan of Java iterators and collections, so I’m going to narrow my focus in this post to only these two (lists and iterators in particular). I will use a variant of the code that I posted in a comment to the article as an example to demonstrate a common Java programming practice.

Here is the elementary code:


return new Iterator() {
    ListIterator iter = list.listIterator();
    boolean pending;
    public boolean hasNext() {
        pending = true;
        while (iter.hasNext()) {
            if (yield(iter.next())) {
                iter.previous();
                return true;
            }
        }
        return false;
    }
    public Object next() {
        if (!pending) hasNext();
        pending = false;
        return iter.next();
    }
    public void remove() {
        if (pending) throw new IllegalStateException();
        iter.remove();
    }
    boolean yield(Object item) {
        return ( conditional expression );
    }
};

This code only makes use of the core Java API and does not depend on any other customised or externally provided classes or libraries. Solutions like these are not directly reusable, but the practice of developing them can be very beneficial because it gives developers the opportunity to do some elementary programming and problem solving of their own for a change. It is very important for Java programmers to get accustomed to this practice because it helps them to know Java much better and exercises their programming abilities. I’ve been using this code for quite some time now and continue to find it useful for filtering Java lists. It may seem a little non intuitive at first, but if you factor out the iteration logic into a reusable adapter class, it suddenly becomes very intuitive and simple.

Here is the simplified code:


return new IteratorAdapter(list) {
    protected boolean yield(Object item) {
        return ( conditional expression );
    }
};

Here is the factored out class:


public abstract class IteratorAdapter
        implements Iterator {
    private ListIterator iter;
    private boolean pending;
    public IteratorAdapter(List list) {
        iter = list.listIterator();
    }
    public boolean hasNext() {
        pending = true;
        while (iter.hasNext()) {
            if (yield(iter.next())) {
                iter.previous();
                return true;
            }
        }
        return false;
    }
    public Object next() {
        if (!pending) hasNext();
        pending = false;
        return iter.next();
    }
    public void remove() {
        if (pending) throw new IllegalStateException();
        iter.remove();
    }
    protected boolean yield(Object item) {
        return true;
    }
}

This factored out class can be reused in any Java application that needs to filter Java lists. It is by no means the most glorified or elegant solution, but rather a simple solution that serves a single purpose and works well with lists. It would be too unreasonable to package this kind of code into a reusable class library. It would be much more reasonable to leave it where it is and submit it as a new idea for improving the Java language (Java 7 maybe?).

The next time you encounter an intrinsic Java programming problem, try and solve it with the core Java API first. It will make you a more knowledgeable Java programmer and could also free your program from a dependency or two.
 
AddThis Social Bookmark Button AddThis Feed Button

Comments»

1. Aviad Ben Dov - August 8, 2007

I agree with you that knowing Java and its core frameworks is extremely important and can save you quite a lot of work, forget dependencies.

However, I think you misunderstood what I was going for. The predicate example I gave was a simple example - However, the yielder solution is a general solution for creating generators.

If you will, you can examine my examples page. The idea is that keeping state for iteration is hard and time-consuming (for a programmer). For making a predicate list, it’s easy; for making an iterator over a graph or a tree, is harder. Much harder.

2. WarpedJavaGuy - August 8, 2007

I agree that you do need a more general solution if you want to cater for various types of structures like trees, graphs, and the like. I think the yielder solution is good for those and more. But if you’re only working with Java collections, then a simpler solution will do.

3. Aviad Ben Dov - August 9, 2007

Agreed. And in fact, up until I needed to iterate a tree, I only used pure Java classes for predicates and the likes.

If you’re having any trouble with using the yielder, please let me know. I am looking for some feedback! :)

4. WarpedJavaGuy - August 9, 2007

Excellent :)

The ability to yield is just one example of a simple yet powerful mechanism that would be useful to have in Java.

I’m sure there are many other similar abstractions that others have discovered and used in their projects and programs.
I’d like to know how they are being reused.

5. Aviad Ben Dov - August 9, 2007

With that I can’t help you, unfortunately… Before writing this thing, I’ve looked around, but couldn’t find anything really (except for people really wishing to have a yield option on Java as well).

6. WarpedJavaGuy - August 10, 2007

There are many other situations where programmers have had to implement missing Java features. I’d like to broaden the discussion and invite everyone to share their unique experiences and how they are reusing their solutions.

7. michaelp - August 11, 2007

Your code is not correct because it requires the user of the Iterator to always call hasNext() prior to next() which is not necessary for standard iterators.

For example if the first element in your collection should not be returned (means should be filtered) but you do not call hasNext() it will be returned by next().

WarpedJavaGuy - August 12, 2007

I have never used iterators in that way, but you are right in that the standard Java iterators do allow it.

I have updated the code to support it.

8. Aviad Ben Dov - August 11, 2007

michaelp - I’d like to just mention that the yield library doesn’t require calling the hasNext() method for it to work. :)

(PR.. PR… ;)

9. Stephen - August 11, 2007

Nice article, concise and useful - I’ve got some code in my current project which could probably make use of this.

A couple of questions:

1) I would have expected that the yield(..) method in IteratorAdapter would be abstract - any reason not to do this?

2) It appears that if a collection is passed to the constructor, then the remove() method will not behave as expected - ie the object will not be removed from the original collection.

WarpedJavaGuy - 12 August, 2007

Stephen,

1) The yield method is not abstract because I wanted the adapter to yield all items by default if no methods are overridden.

2) Oops, the constructor that accepted a collection did have that problem. I have removed that constructor. It would be nice to be able to support any type of collection, but it is not very viable with a list based solution like this one.

10. Bill Klingon - August 11, 2007

Actually I hope no one follows your advice.

Do you know how many people code and recode the same algorithms over and over?

Do you know that they are wasting precious time and at the same time introducing subtle bugs that will take months if not years to detect?

I know this post will not change things, people will code and recode things that are already written in libraries just for the sake of it, because it is so much fun to code, but it is a shame on the profession.

Do you imagine you ask someone to build your house and instead of them buying standard bricks, try to invent how to create bricks, then how to create hammers, … If you saw that you would be very upset, but in the software development world this attitude is considered correct.

I do not mean we should build prototypes, and if you want to create your own database engine, be my guest, but please first read about the subject and do it own your time. When the thing works, come to show to it to me and make sure I’m saving a lot of time because of your invention!!! ;-D

11. WarpedJavaGuy - August 12, 2007

Thanks Bill. It sure is important to check, test, and double check and test. It’s those very subtleties you mention that we all have to learn to become better programmers.

I have since corrected the problems identified in the above comments.

12. WarpedJavaGuy - August 22, 2007

I recently found a similar post here about whether or not frameworks and API’s can limit developers’ imaginations.

I realise that solving the same problems over and over again can be counter productive and can sometimes even lead to bugs being introduced, but I think there is good value in it from a personal development and learning perspective. Bugs can be fixed and even frameworks have bugs that need fixing. More importantly though, it highlights the need to have specific low level solutions like these integrated into the core language API. That way we wouldn’t have to recode them or look for them in other frameworks.

By trying to solve problems using the core API first, we can better identify key missing features and propose to have them added to the language instead of just implementing them in frameworks. That would create a win-win situation for all programmers. Frameworks could then focus on solving the more higher level problems.

13. Elvis » Blog Archive » Favorite Programming Quotes 2007 - January 12, 2008

[...] frameworks and more programs the sooner we’ll become better programmers. – Warped Java Guy Elementary Java Solutions Starting a startup is hard, but having a 9 to 5 job is hard too, and in some ways a worse kind of [...]