We can't directly pass the whole method as an argument to another method. Instead, we can call the method from the argument of another method. // pass method2 as argument to method1 public void method1(method2()); Here, the returned value from method2() is assigned as an argument to method1() .
In JavaScript, passing a function as a parameter to another function is similar to passing values. The way to pass a function is to remove the parenthesis () of the function when you assign it as a parameter. In the following sections, a function pass is demonstrated as a parameter.
We learned that parameter passing in Java is always Pass-by-Value. However, the context changes depending upon whether we're dealing with Primitives or Objects: For Primitive types, parameters are pass-by-value.
There are two ways to call a method with parameters in java: Passing parameters of primtive data type and Passing parameters of reference data type. 4. in Java, Everything is passed by value whether it is reference data type or primitive data type.
Edit: as of Java 8, lambda expressions are a nice solution as other answers have pointed out. The answer below was written for Java 7 and earlier...
Take a look at the command pattern.
// NOTE: code not tested, but I believe this is valid java...
public class CommandExample
{
public interface Command
{
public void execute(Object data);
}
public class PrintCommand implements Command
{
public void execute(Object data)
{
System.out.println(data.toString());
}
}
public static void callCommand(Command command, Object data)
{
command.execute(data);
}
public static void main(String... args)
{
callCommand(new PrintCommand(), "hello world");
}
}
Edit: as Pete Kirkham points out, there's another way of doing this using a Visitor. The visitor approach is a little more involved - your nodes all need to be visitor-aware with an acceptVisitor()
method - but if you need to traverse a more complex object graph then it's worth examining.
In Java 8, you can now pass a method more easily using Lambda Expressions and Method References. First, some background: a functional interface is an interface that has one and only one abstract method, although it can contain any number of default methods (new in Java 8) and static methods. A lambda expression can quickly implement the abstract method, without all the unnecessary syntax needed if you don't use a lambda expression.
Without lambda expressions:
obj.aMethod(new AFunctionalInterface() {
@Override
public boolean anotherMethod(int i)
{
return i == 982
}
});
With lambda expressions:
obj.aMethod(i -> i == 982);
Here is an excerpt from the Java tutorial on Lambda Expressions:
Syntax of Lambda Expressions
A lambda expression consists of the following:
A comma-separated list of formal parameters enclosed in parentheses. The CheckPerson.test method contains one parameter, p, which represents an instance of the Person class.
Note: You can omit the data type of the parameters in a lambda expression. In addition, you can omit the parentheses if there is only one parameter. For example, the following lambda expression is also valid:p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25
The arrow token,
->
A body, which consists of a single expression or a statement block. This example uses the following expression:
p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25
If you specify a single expression, then the Java runtime evaluates the expression and then returns its value. Alternatively, you can use a return statement:
p -> { return p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25; }
A return statement is not an expression; in a lambda expression, you must enclose statements in braces ({}). However, you do not have to enclose a void method invocation in braces. For example, the following is a valid lambda expression:
email -> System.out.println(email)
Note that a lambda expression looks a lot like a method declaration; you can consider lambda expressions as anonymous methods—methods without a name.
Here is how you can "pass a method" using a lambda expression:
interface I {
public void myMethod(Component component);
}
class A {
public void changeColor(Component component) {
// code here
}
public void changeSize(Component component) {
// code here
}
}
class B {
public void setAllComponents(Component[] myComponentArray, I myMethodsInterface) {
for(Component leaf : myComponentArray) {
if(leaf instanceof Container) { // recursive call if Container
Container node = (Container)leaf;
setAllComponents(node.getComponents(), myMethodInterface);
} // end if node
myMethodsInterface.myMethod(leaf);
} // end looping through components
}
}
class C {
A a = new A();
B b = new B();
public C() {
b.setAllComponents(this.getComponents(), component -> a.changeColor(component));
b.setAllComponents(this.getComponents(), component -> a.changeSize(component));
}
}
Class C
can be shortened even a bit further by the use of method references like so:
class C {
A a = new A();
B b = new B();
public C() {
b.setAllComponents(this.getComponents(), a::changeColor);
b.setAllComponents(this.getComponents(), a::changeSize);
}
}
Since Java 8 there is a Function<T, R>
interface (docs), which has method
R apply(T t);
You can use it to pass functions as parameters to other functions. T is the input type of the function, R is the return type.
In your example you need to pass a function that takes Component
type as an input and returns nothing - Void
. In this case Function<T, R>
is not the best choice, since there is no autoboxing of Void type. The interface you are looking for is called Consumer<T>
(docs) with method
void accept(T t);
It would look like this:
public void setAllComponents(Component[] myComponentArray, Consumer<Component> myMethod) {
for (Component leaf : myComponentArray) {
if (leaf instanceof Container) {
Container node = (Container) leaf;
setAllComponents(node.getComponents(), myMethod);
}
myMethod.accept(leaf);
}
}
And you would call it using method references:
setAllComponents(this.getComponents(), this::changeColor);
setAllComponents(this.getComponents(), this::changeSize);
Assuming that you have defined changeColor() and changeSize() methods in the same class.
If your method happens to accept more than one parameter, you can use BiFunction<T, U, R>
- T and U being types of input parameters and R being return type. There is also BiConsumer<T, U>
(two arguments, no return type). Unfortunately for 3 and more input parameters, you have to create an interface by yourself. For example:
public interface Function4<A, B, C, D, R> {
R apply(A a, B b, C c, D d);
}
Use the java.lang.reflect.Method
object and call invoke
First define an Interface with the method you want to pass as a parameter
public interface Callable {
public void call(int param);
}
Implement a class with the method
class Test implements Callable {
public void call(int param) {
System.out.println( param );
}
}
// Invoke like that
Callable cmd = new Test();
This allows you to pass cmd as parameter and invoke the method call defined in the interface
public invoke( Callable callable ) {
callable.call( 5 );
}
While this is not yet valid for Java 7 and below, I believe that we should look to the future and at least recognize the changes to come in new versions such as Java 8.
Namely, this new version brings lambdas and method references to Java (along with new APIs, which are another valid solution to this problem. While they still require an interface no new objects are created, and extra classfiles need not pollute output directories due to different handling by the JVM.
Both flavors(lambda and method reference) require an interface available with a single method whose signature is used:
public interface NewVersionTest{
String returnAString(Object oIn, String str);
}
Names of methods will not matter from here on. Where a lambda is accepted, a method reference is as well. For example, to use our signature here:
public static void printOutput(NewVersionTest t, Object o, String s){
System.out.println(t.returnAString(o, s));
}
This is just a simple interface invocation, up until the lambda1 gets passed:
public static void main(String[] args){
printOutput( (Object oIn, String sIn) -> {
System.out.println("Lambda reached!");
return "lambda return";
}
);
}
This will output:
Lambda reached!
lambda return
Method references are similar. Given:
public class HelperClass{
public static String testOtherSig(Object o, String s){
return "real static method";
}
}
and main:
public static void main(String[] args){
printOutput(HelperClass::testOtherSig);
}
the output would be real static method
. Method references can be static, instance, non-static with arbitrary instances, and even constructors. For the constructor something akin to ClassName::new
would be used.
1 This is not considered a lambda by some, as it has side effects. It does illustrate, however, the use of one in a more straightforward-to-visualize fashion.
Last time I checked, Java is not capable of natively doing what you want; you have to use 'work-arounds' to get around such limitations. As far as I see it, interfaces ARE an alternative, but not a good alternative. Perhaps whoever told you that was meaning something like this:
public interface ComponentMethod {
public abstract void PerfromMethod(Container c);
}
public class ChangeColor implements ComponentMethod {
@Override
public void PerfromMethod(Container c) {
// do color change stuff
}
}
public class ChangeSize implements ComponentMethod {
@Override
public void PerfromMethod(Container c) {
// do color change stuff
}
}
public void setAllComponents(Component[] myComponentArray, ComponentMethod myMethod) {
for (Component leaf : myComponentArray) {
if (leaf instanceof Container) { //recursive call if Container
Container node = (Container) leaf;
setAllComponents(node.getComponents(), myMethod);
} //end if node
myMethod.PerfromMethod(leaf);
} //end looping through components
}
Which you'd then invoke with:
setAllComponents(this.getComponents(), new ChangeColor());
setAllComponents(this.getComponents(), new ChangeSize());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With