in reply to Perl Functionality in Java

I don't know of any projects like this, but ++ to you samurai; I think we ought to do it, and to start us off here's a first run implementation of map, applicable to grep. Its weakness is that the loop iterations and return values must be defined by the user, however I'm not sure yet how to get similar behavior to setting $_ as in Perl. In any case, here goes:

public class Mapper { // Define an interface that each block will implement. Note that // we use java.lang.Object here so this will work with any class. interface MapBlock { public Object[] run(Object[] list); } // Define our map method, which calls the methods declared in the // MapBlock interface and returns the outcome. public static Object[] map(MapBlock block, Object[] list) { Object[] out =; return out; } // Define a main to test the idea. public static void main(String[] args) { // Test arguments, lowercase 'foo' and 'bar' Object[] objects = { new String("foo"), new String("bar") }; // Call the map function, passing an anonymous class implementin +g // interface MapBlock containing the code we want to run. Object[] new_list = map(new MapBlock() { public Object[] run(Object[] list) { Object[] out = new Object[list.length]; for (int i = 0; i < list.length; i++) { String str = (String)list[i]; // Create uppercase versions out[i] = str.toUpperCase(); } return out; } }, objects); // end of MapBlock, second param objects // Test to see what our new Object array contains. System.out.println((String)new_list[0] + (String)new_list[1]); } }

prints "FOOBAR".

Update: The fundamental concept at work here (and in the reply immediate below) is that of the anonymous class. An anonymous class may be declared in two ways:

new interface-name () { class-body } // as in this node -or- new class-name ([argument-list]) { class-body } // as in the reply

The call new MapBlock creates a new object that implements the interface MapBlock, which amounts to an is-a relationship. The class itself anonymous, but it's-a MapBlock. That means we can create a one-off class implementing particular behavior, and because the compiler is aware of the MapBlock interface, it'll let you create a new class that implements it. This is closest we can get AFAIK to passing a block of code to a function. The problem in this version though is that all the functionality must be packed into the anonymous implementation, including the code for iterating through the list, as an interface cannot include implementation. But that means this isn't yet like map.

So, below I try the other option, subclassing another class. In this case new MapBlock creates an anonymous subclass of MapBlock, which means we can inherit a constructor and some implementation behavior. The idea now is to pack the implicit map functions, e.g., iterating over a list and placing the results into an array, into the superclass. The anonymous subclass now only has to implement the abstract method processElement(Object obj) so it can be called from the superclass's run method, and this gets us pretty close to the map BLOCK LIST behavior we want./Update.

Now it's on to foreach, because I really despise the normal, braindead Java 'for' loops!

cheers, fever

Replies are listed 'Best First'.
Re: Re: Perl Functionality in Java
by djantzen (Priest) on Nov 08, 2002 at 14:20 UTC

    Okay, I've got a major improvement on this. Rather than forcing the user to handle iteration through the loop and to compile the return list -- making this implementation of highly dubious value over a normal 'for' loop -- we define an abstract superclass from which to inherit rather an interface to implement:

    public abstract static class MapBlock { public Object[] run(Object[] list) { Object[] out = new Object[list.length]; // begin loop through list for (int i = 0; i < list.length; i++) { // call processElement on ourself and collect element return +ed Object new_obj = this.processElement(list[i]); out[i] = new_obj; } return out; } public abstract Object processElement(Object obj); // This might alternatively return an Object array for greater fle +xibility. // 'run' would require slight alterations to deal with an array co +ming back. // Thanks for the idea to [jdporter] }

    The original definition of map remains the same. Then below, we can simplify the anonymous class to the point where this is really starting to look like map!

    Object[] new_list = map(new MapBlock() { public Object processElement(Object obj) { String str = (String)obj; return str.toUpperCase(); } }, objects); // end of MapBlock, second param objects

    It's times like these I say booyah! ; )