http://qs321.pair.com?node_id=211169


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 = block.run(list); 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