Java Forum / General / September 2006
Can a method be a parameter of another method in Java?
Shawn - 13 Sep 2006 13:46 GMT Hi,
In a precedual language world, a method can take a parameter which is a method by itself. For example,
<psudo-code>
sum_from_a_to_b(myFunc, a, b); //a is 1, b is 5
by passing different myFunc,
sum_from_a_to_b=1+2+3+4+5; or sum_from_a_to_b=1^2+2^2+3^2+4^2+5^2; or sum_from_a_to_b=1^3+2^3+3^3+4^3+4^3; or sum_from_a_to_b=(1+50)^2+(2+50)^2+...+(5+50)^2; or anything you specified in myFunc.
This strategy is very powerful because it elevated one level higher by abstraction. Can Java do something similar? If not, how Java get around it?
Thank you very much. I greatly appreciate any feedback.
Ingo R. Homann - 13 Sep 2006 13:51 GMT Hi,
> Hi, > [quoted text clipped - 19 lines] > This strategy is very powerful because it elevated one level higher by > abstraction. Can Java do something similar? Of course it can, see below. A great advantage of Java is, that its solution is also typesafe!
Ciao, Ingo
interface Mapper { int map(int d); }
class Test {
double sum(Mapper m, int a, int b) { int sum=0; for(int i=a;i<=b;i++) { sum+=m.map(i); } return sum; }
void test() { System.out.println(sum( new Mapper(){public int map(int x) {return x*x;}}, 5,10)); System.out.println(sum( new Mapper(){public int map(int x) {return (x+50)*(x+50);}}, 5,10)); // ... }
}
Shawn - 13 Sep 2006 14:10 GMT > Of course it can, see below. A great advantage of Java is, that its > solution is also typesafe! [quoted text clipped - 27 lines] > > } Fantastic! Thank you very much. I didn't realize interface can be such a use--place holder. I thought interface was only used in inheritance.
One more question about the "public" word:
interface Mapper { int map(int d); //Did you forget "public" here? } .. System.out.println(sum( new Mapper(){public int map(int x) {return x*x;}}, 5,10)); //I assume you add public here so Mapper m can access .map(). If you omit it above, can you enforce it now?
Thank you again.
Michael Rauscher - 13 Sep 2006 14:35 GMT Shawn schrieb:
>> Of course it can, see below. A great advantage of Java is, that its >> solution is also typesafe! [quoted text clipped - 36 lines] > int map(int d); //Did you forget "public" here? > } No, Ingo didn't forget the public. A interface only have public methods so the public keyword may be omitted.
Bye Michael
Ingo R. Homann - 13 Sep 2006 15:52 GMT Hi,
> Fantastic! Thank you very much. I didn't realize interface can be such a > use--place holder. I thought interface was only used in inheritance. I do not see any difference!
A class can implement an interface and therefore must implement the method defined in this interface. So, the class is a subtype of the interface (->inheritance). Now, if you want to access the method, you only need a reference to some Object which has the type/subtype of the interface, therefore, the interface is a place holder (if you want to call it so)...
Ciao, Ingo
Bent C Dalager - 13 Sep 2006 16:56 GMT >Hi, > [quoted text clipped - 6 lines] >method defined in this interface. So, the class is a subtype of the >interface (->inheritance). I think we should maintain a distinction between inheritance and implementation: the class does not inherit from the interface, but rather it implements the interface. A class can only inherit from other classes, not from interfaces.
I would therefore say that Shawn is right in concluding that interfaces aren't just used for inheritance. (And to the extent that interfaces are involved in inheritance at all, it's only when they inherit from other interfaces - but interface inheritance is somewhat an different beast than class inheritance.)
Cheers Bent D
 Signature Bent Dalager - bcd@pvv.org - http://www.pvv.org/~bcd powered by emacs
AndrewMcDonagh - 13 Sep 2006 20:15 GMT >> Hi, >> [quoted text clipped - 19 lines] > Cheers > Bent D Actually they are called Interface Inheritance and Implementation Inheritance
Java keywords is 'implements' but that is not the OO term.
This is why Java supports Multiple Interface Inheritance, but not Multiple Implementation Inheritance.
Andrew
Mark Space - 13 Sep 2006 19:42 GMT >> Of course it can, see below. A great advantage of Java is, that its >> solution is also typesafe! [quoted text clipped - 11 lines] >> ... >> }
> Fantastic! Thank you very much. I didn't realize interface can be such a > use--place holder. I thought interface was only used in inheritance. Don't overlook the use of Interface in conjunction with other forms of inheritance at the same time:
class hickey extends dohickey implements blah, Mapper { ... }
Now a class that does a lot of things (like things you need for your design) can also be used for a Mapper object. This particular pattern happens a lot in Swing, for example, especially for action listeners, so be on the look out for it.
Also, there is another way of doing what you ask. The Method object corresponds much more closely to a C function pointer:
class myInvoker( Method func_ptr ) { funct_ptr.invoke(); }
static main (args[]) { Object o = new Integer(); Class[] parameterTypes = new Class[] {String.class}; Method m = = c.getMethod("concat", parameterTypes);
myInvoker( m ); }
Except that there's a lot more needed than that (I omitted big try ... catch blocks, for starters). However, the Method object can be used to sling methods around something like C functions.
What this is useful for is when you can't use Interfaces. For example, you are passed an Object, and you'd like to be able to access methods by name. A method called "getName" which returns a string, and a method called "setName(String)" could be used to set a property called Name in the Object, and there's no need for any Interface or inheritance at all. This provides a lot of flexibility for your programs.
You can also look at an Object, and find what Interfaces it implements, and even pick and choose which Interfaces you want. For example, you might want Mapper2_0, but you'll settle for Mapper1_0. Again, lots of flexibility for your programs.
The whole subject is called Reflection, for more go to:
Finding Interface: http://java.sun.com/docs/books/tutorial/reflect/class/getInterfaces.html
Invoking methods, the real example: http://java.sun.com/docs/books/tutorial/reflect/object/invoke.html
More reflection, the whole she-bang: http://java.sun.com/docs/books/tutorial/reflect/index.html
Shawn - 13 Sep 2006 18:50 GMT Hi,
Could you provide me one more example to achieve the following effect in Java? Thank you very much.
var a = [1,2,3]; for (i=0; i<a.length; i++) { a[i] = a[i] * 2; } for (i=0; i<a.length; i++) { alert(a[i]); } Doing something to every element of an array is pretty common, and you can write a function that does it for you:
function map(fn, a) { for (i = 0; i < a.length; i++) { a[i] = fn(a[i]); } } Now you can rewrite the code above as:
map( function(x){return x*2;}, a ); map( alert, a );
Shawn - 13 Sep 2006 19:43 GMT > Hi, > [quoted text clipped - 26 lines] > map( function(x){return x*2;}, a ); > map( alert, a ); Sorry. I try to do it myself. If anything wrong, please point it out for me. Thank you.
interface Mapper { void map(int[] d); }
class Test {
void doSomethingToArray(Mapper m, int[] aArray) { m.map(aArray); } //end of method doSomethingToArray
Mapper squareArray = new Mapper() { void map(int[] a) { for (int i=0; i<a.length; i++) { a[i] *= a[i]; } } }
Mapper printArray = new Mapper() { void map(int[] a) { for (int i=0; i<a.length; i++) { System.out.println(a[i]); } } }
void test() { int[] a={2, 4, 6, 8}; doSomethingToArray(squareArray, a); doSomethingToArray(printArray, a); }
} //end of class Test
Shawn - 13 Sep 2006 20:02 GMT > Hi, > [quoted text clipped - 26 lines] > map( function(x){return x*2;}, a ); > map( alert, a ); I tried the following file Test.java. It didn't work.
/* For testing passing a method as a method parameter */
interface Mapper { void map(int[] d); }
class Test {
void doSomethingToArray(Mapper m, int[] aArray) { m.map(aArray); } //end of method doSomethingToArray
Mapper squareArray = new Mapper() { void map(int[] a) { for (int i=0; i<a.length; i++) { a[i] *= a[i]; } } }
Mapper printArray = new Mapper() { void map(int[] a) { for (int i=0; i<a.length; i++) { System.out.println(a[i]); } } }
static int[] a={2, 4, 6, 8};
public static void main(String[] args) { doSomethingToArray(squareArray, a); doSomethingToArray(printArray, a); }
} //end of class Test
Below is the error message. I cannot solve it. Back to the interface issue, I am not allowed to instantiate an interface even I implement its method?
Thank you very much for your help.
>javac Test.java ---------- 1. ERROR in Test.java (at line 25) Mapper printArray = new Mapper() { ^^^^^^ Syntax error on token "Mapper", ";", "," expected ---------- 2. ERROR in Test.java (at line 39) doSomethingToArray(squareArray, a); ^^^^^^^^^^^ Cannot make a static reference to the non-static field squareArray ---------- 3. ERROR in Test.java (at line 40) doSomethingToArray(printArray, a); ^^^^^^^^^^ Cannot make a static reference to the non-static field printArray ---------- 3 problems (3 errors)
AndrewMcDonagh - 13 Sep 2006 20:17 GMT >> Hi, >> [quoted text clipped - 59 lines] > } > } } ;
you are missing a ';' on the '}' above
> static int[] a={2, 4, 6, 8}; > [quoted text clipped - 30 lines] > ---------- > 3 problems (3 errors) Ingo R. Homann - 14 Sep 2006 08:16 GMT Hi,
> /* > For testing passing a method as a method parameter [quoted text clipped - 29 lines] > } > } Besides the missing ';', there is another design-flaw IMHO. I would do it like this:
interface Mapper { int map(int a); }
class Test { void doSomethingToArray(int[] as, Mapper m) { for(int i=0;i<as.length;i++) { as[i]=m.map(as[i]); } } }
Mapper square=new Mapper() { int map(int i) { return i*i; } }
Mapper print=new Mapper() { int map(int i) { System.out.println(i); return i; // (*) } }
(*) here you can see, that "printing" is not really a kind of "Mapper"-function.
Ciao, Ingo
Shawn - 14 Sep 2006 13:57 GMT > Besides the missing ';', there is another design-flaw IMHO. I would do > it like this: [quoted text clipped - 29 lines] > Ciao, > Ingo Thank you. Could you kindly provide "public static void main() " to show me how to use it. As you see, I am a little lost here: in the same Java file or in the different file? If in the same file, what the file name should be?(Test.java or interface.java?) Do I have to make doSomethingToArray static?
I still like my previous not-running program, because in yours, as you said, Mapper print is "silly" and in the for loop inside doSomethingToArray, as[i] = m.map(as[i]) is not needed in my program. My code is more intuitive. The reason I want to pass a method as a parameter into another method is to have more abstraction(clear mind clutter). Your implementation brings other extra into the code. My goal is half-achieved, though.
Ingo R. Homann - 15 Sep 2006 08:49 GMT Hi,
> Thank you. Could you kindly provide "public static void main() " to show > me how to use it. As you see, I am a little lost here: in the same Java > file or in the different file? If in the same file, what the file name > should be?(Test.java or interface.java?) Do I have to make > doSomethingToArray static? OK, you have solved this, as I see...
> I still like my previous not-running program, because in yours, as you > said, Mapper print is "silly" Well, it is "silly" in your program as well, because, your "PrintMapper" is no "Mapper" at all, because it "maps" nothing!
> and in the for loop inside > doSomethingToArray, as[i] = m.map(as[i]) is not needed in my program. The opposite is true: You need the loop *twice* (or even more, if you want to implement other Mappers)!
And you have a method "doSomethingToArray" which does not do anything (except calling another method - which you could do directly).
> My code is more intuitive. I think, the opposite is true. (But I think there is no way to find out who is right - we could others let vote for it... ;-)
Ciao, Ingo
Shawn - 14 Sep 2006 19:33 GMT /* For testing passing a method as a method parameter */
interface Mapper { void map(int[] d); }
class Demo { void doSomethingToArray(Mapper m, int[] aArray) { m.map(aArray); } //end of method doSomethingToArray
Mapper squareArray = new Mapper() { public void map(int[] a) { for (int i=0; i<a.length; i++) { a[i] *= a[i]; } } };
Mapper printArray = new Mapper() { public void map(int[] a) { for (int i=0; i<a.length; i++) { System.out.println(a[i]); } } };
private int[] a = new int[3];
public static void main(String[] args) { Demo aDemo = new Demo(); aDemo.a[0] = 1; aDemo.a[1] = 2; aDemo.a[2] = 3; aDemo.doSomethingToArray(aDemo.printArray, aDemo.a); aDemo.doSomethingToArray(aDemo.squareArray, aDemo.a); aDemo.doSomethingToArray(aDemo.printArray, aDemo.a); }
} //end of class Demo
Shawn - 14 Sep 2006 19:35 GMT Following is my code. It runs very well.
Thank you for your any feedback.
/* For testing passing a method as a method parameter */
interface Mapper { void map(int[] d); }
class Demo { void doSomethingToArray(Mapper m, int[] aArray) { m.map(aArray); } //end of method doSomethingToArray
Mapper squareArray = new Mapper() { public void map(int[] a) { for (int i=0; i<a.length; i++) { a[i] *= a[i]; } } };
Mapper printArray = new Mapper() { public void map(int[] a) { for (int i=0; i<a.length; i++) { System.out.println(a[i]); } } };
private int[] a = new int[3];
public static void main(String[] args) { Demo aDemo = new Demo(); aDemo.a[0] = 1; aDemo.a[1] = 2; aDemo.a[2] = 3; aDemo.doSomethingToArray(aDemo.printArray, aDemo.a); aDemo.doSomethingToArray(aDemo.squareArray, aDemo.a); aDemo.doSomethingToArray(aDemo.printArray, aDemo.a); }
} //end of class Demo
Michael Rauscher - 15 Sep 2006 09:40 GMT Shawn schrieb:
> Following is my code. It runs very well. > > Thank you for your any feedback. With respect to what Ingo already mentioned, I can't tell you something new.
I expect doSomethingToArray to do something with each element of the array. It doesn't. Perhaps it's just that my English isn't well enough to estimate this, but given the body of your method I'd name it doSomethingWithArray.
That's not nice because can call the Mapper method directly as good as call it indirectly via doSomethingToArray. Therefore your doSomethingToArray seems to be rather useless to me.
The next point goes to Ingo, too: You need to iterate over the array in every mapper.
Regarding the map method: first, I thought it's wrong because it doesn't seem to map. OTOH doing nothing with the array results in an identity mapping. But there's one more issue: It's questionable if mapping may involve changing...
In the end, I'd vote for Ingo's solution ;)
Bye Michael
Shawn - 15 Sep 2006 14:55 GMT Thank you all. I don't want to argue the term "Mapper" and what it suppose to do. I still like my code better.
My code:
void doSomethingToArray(Mapper m, int[] aArray) { m.map(aArray); } //end of method doSomethingToArray
aDemo.doSomethingToArray(aDemo.printArray, aDemo.a); aDemo.doSomethingToArray(aDemo.squareArray, aDemo.a);
All the mess(e.g. for loop) are suppressed into the new Mapper(...). At the above level, it is so clean.
Your code:
void doSomethingToArray(int[] as, Mapper m) { for(int i=0;i<as.length;i++) { as[i]=m.map(as[i]); }
Ingo R. Homann - 18 Sep 2006 08:31 GMT Hi,
> Thank you all. I don't want to argue the term "Mapper" and what it > suppose to do. I still like my code better. OK, now imagine, you have implemented 10 Mappers and suddenly, you want to map not only int-Arrays, but also Lists of Integers.
With your approach, you have to change your interface and have to implement 10 new methods (one for every Mapper-implementation).
With my appraoch, you only have to implement *one* method:
public List<Integer> apply(List<Integer> is, Mapper m) { List<Integer> l=new ArrayList<Integer>(is.size()); for(Integer i:is) { l.add(m.map(i)); } return l; }
Ciao, Ingo
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|