Can a method be a parameter of another method in Java?

S

Shawn

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.
 
I

Ingo R. Homann

Hi,
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?

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));
// ...
}

}
 
S

Shawn

Ingo said:
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));
// ...
}

}

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.
 
M

Michael Rauscher

Shawn said:
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?
}

No, Ingo didn't forget the public. A interface only have public methods
so the public keyword may be omitted.

Bye
Michael
 
I

Ingo R. Homann

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
 
B

Bent C Dalager

Hi,


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).

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
 
S

Shawn

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 = a * 2;
}

for (i=0; i<a.length; i++)
{
alert(a);
}
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 = fn(a);
}
}
Now you can rewrite the code above as:

map( function(x){return x*2;}, a );
map( alert, a );
 
M

Mark Space

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
 
S

Shawn

Shawn said:
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 = a * 2;
}

for (i=0; i<a.length; i++)
{
alert(a);
}
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 = fn(a);
}
}
Now you can rewrite the code above as:

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 *= a;
}
}
}

Mapper printArray = new Mapper()
{
void map(int[] a)
{
for (int i=0; i<a.length; i++)
{
System.out.println(a);
}
}
}

void test() {
int[] a={2, 4, 6, 8};
doSomethingToArray(squareArray, a);
doSomethingToArray(printArray, a);
}

} //end of class Test
 
S

Shawn

Shawn said:
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 = a * 2;
}

for (i=0; i<a.length; i++)
{
alert(a);
}
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 = fn(a);
}
}
Now you can rewrite the code above as:

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 *= a;
}
}
}

Mapper printArray = new Mapper() {
void map(int[] a)
{
for (int i=0; i<a.length; i++)
{
System.out.println(a);
}
}
}

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
 
A

AndrewMcDonagh

Bent said:
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

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
 
A

AndrewMcDonagh

Shawn said:
Shawn said:
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 = a * 2;
}
for (i=0; i<a.length; i++)
{
alert(a);
}
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 = fn(a);
}
}
Now you can rewrite the code above as:

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 *= a;
}
}
}

Mapper printArray = new Mapper() {
void map(int[] a)
{
for (int i=0; i<a.length; i++)
{
System.out.println(a);
}
}

} ;

you are missing a ';' on the '}' above
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
 
I

Ingo R. Homann

Hi,
/*
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 *= a;
}
}
}

Mapper printArray = new Mapper() {
void map(int[] a)
{
for (int i=0; i<a.length; i++)
{
System.out.println(a);
}
}
}


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=m.map(as);
}
}
}

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
 
S

Shawn

Ingo said:
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=m.map(as);
}
}
}

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

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 = m.map(as) 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.
 
S

Shawn

/*
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 *= a;
}
}
};

Mapper printArray = new Mapper() {
public void map(int[] a)
{
for (int i=0; i<a.length; i++)
{
System.out.println(a);
}
}
};

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
 
S

Shawn

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 *= a;
}
}
};

Mapper printArray = new Mapper() {
public void map(int[] a)
{
for (int i=0; i<a.length; i++)
{
System.out.println(a);
}
}
};

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
 
I

Ingo R. Homann

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 = m.map(as) 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
 
M

Michael Rauscher

Shawn said:
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
 
S

Shawn

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=m.map(as);
}
 
I

Ingo R. Homann

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top