views:

90

answers:

3

I have a Abstract Iterator class which has this function

void iterate(){
    while(this.hasnext()){
        ..this.next()..
    }
}

How do I pass in any arbitrary function that will be applied to the next element. For example, is there a way to do iterate(print)?

+9  A: 

In Java, it is impossible to directly pass functions in as parameters. Instead you need to set up an interface with one method like so:

interface Operate {
    public void operate(Object o);
}

Then, you need to implement the interface for each different operation you would like to perform on the Object.

An example implementation.

class Print implements Operate {
    public void operate(Object o){
        System.out.println(o.toString());
    }
}

Implementation in your code:

iterate(Operate o){
    while(this.hasnext()){
        o.operate(this.next());
    }
}
jjnguy
Basically this is the only possibility at the moment, no closures even in Java 7.
Esko
The decision to remove them was a sad decision :(
Malaxeur
This is correct, just thought I'd point out that this is known as the Command Pattern, a very useful pattern that you will begin to use instinctively after you've used it a few times.
vickirk
A: 

Are you assuming that print is a function? Java does not have function pointers or real closures or anything that lets you pass arbitrary functions to other functions, like you would see in more functional languages. You can fake this by creating a Function interface, which has one method,

void apply(Object arg)

You can then create different classes that implement Function and pass those into your iterate method. In your example, you would do something like this perhaps:

    public class PrintFunction implements Function {
        void apply(Object arg) {
              System.out.println(arg.toString());
        }
    }
Peter Recore
+1  A: 

I would reconsider the naming to clarify the semantics:

Having a method in the iterator:

public <T> Object[] apply (Action<T> action, Object context) {
   List<T> results = new ArrayList<T>();
   while(hasNext()) {
       results.add(action.invoke(this.next(), context));
   }
   T[] r = new T[results.size()];
   return results.toArray(r);
}


public interface Action <T> {
   public T invoke (Object target, Object context);
}

Context can be null, but in some cases you really need some sort of pseudo closure to take actions that require context. To make this more robust, you can consider adding exception handling.