3

I have a class with bunch of methods. In another class, I need to write a method, that handles the input values. To that method, I want to pass the method of the class that I want to call. How can we do that with Java after 1.8?

There are similar questions already, but those usually assume that we can use an interface with a single method, therefore can use lambda expressions, etc.

class MyClass {
    public Object myToString(String a) {
        return new String(a);
    }

    public Object myToString(String a, String b) {
       return new String(a + ", " + b);
    }

    public Object mySum(int a) {
        return new Integer(a);
    }

    public Object mySum(int a, int b) {
        return new Integer(a + b);
    }
}

class Test {
    public Object handleInputs(MyClass myClass, MethodAsParameter theMethod, List<Object> inputs) {
        if (type of inputs are Strings) {
            myClass.myToString(inputs.get(0));
        } else if (.....) {
            myClass.mySum(inputs.get(0));
        }
    }
}
newwebdev
  • 407
  • 2
  • 7
  • 13
  • You don't pass the method, you pass the value to those methods and get a result back.(After creating an instance of the class in which your functions reside). – Khan Saab Mar 14 '19 at 19:05
  • You are not using `theMethod` in `handleInputs` – fps Mar 14 '19 at 20:01

3 Answers3

6

Since Java 8 you can use method reference. Method references can be assigned to Function<A, B> functional interface variables and their subclasses.

For example, method with such signature:

class Test {
    public static int DoSomething(String s) {...}
}

can be assigned to a Function<String, Integer> variable like:

Function<String, Integer> method = Test::DoSomething;

and then called:

int result = method.apply("Hello!");

So with small improvements in your code, this is the way you can use your methods as method references and passed to other function as parameters.

class MyClass {

    public static String myToString(String a, String b) {
        return a + ", " + b;
    }

    //notice the boxing in here
    public static int mySum(int a, int b) {
        return a + b;
    }

    //not kind of an revolutionary function, just for demonstration
    public static<T> T Invoke(BinaryOperator<T> bo, T o1, T o2) {
        return bo.apply(o1, o2);
    }


    public static void main(String[] args) {

        int sum = Invoke(MyClass::mySum, 10, 20);
        String str = Invoke(MyClass::myToString, "a", "b");

        System.out.println(sum);
        System.out.println(str);

}

}

t4dohx
  • 675
  • 4
  • 24
2

I think something like this is as far as you would get:

import java.util.List;
import java.util.Arrays;
import java.util.function.Function;
import java.util.function.BiFunction;

class MyClass {
    public Object myToString(String a) {
        return new String(a);
    }

    public Object myToString(String a, String b) {
       return new String(a + ", " + b);
    }

    public Object mySum(int a) {
        return Integer.valueOf(a);
    }

    public Object mySum(int a, int b) {
        return Integer.valueOf(a + b);
    }
}

public class MethodParams {
    public static Object handleInputs(Function<Object,Object> method, List<Object> inputs) {
        return method.apply(inputs.get(0));
    }

    public static Object handleInputs(BiFunction<Object,Object,Object> method, List<Object> inputs) {
        return method.apply(inputs.get(0), inputs.get(1));
    }    

    public static void main(String args[]) {
        MyClass mc = new MyClass();

        String str = (String)handleInputs((a) -> mc.myToString((String)a), Arrays.asList("string"));
        System.out.println(str); // string

        Integer sum = (Integer)handleInputs((a) -> mc.mySum((int)a), Arrays.asList(1));
        System.out.println(sum); // 1

        Integer sum2 = (Integer)handleInputs((a,b) -> mc.mySum((int)a, (int)b), Arrays.asList(1, 2));
        System.out.println(sum2); // 3
    }
}

Not very nice, but at least you have some leeway as to which method you want to use. Code as demonstrated here has lots of casts due to using Objects - using generic types as demonstrated by t2dohx is better way of doing this, but even further from your question.

eis
  • 51,991
  • 13
  • 150
  • 199
0

Here is a simple example:

public class TestMain {

    public static void main(String [] args) {
        Long a = 15L, b = 20L;
        Long sum = combineTwoNumbers(a, b, (p1, p2) -> p1 + p2);
        Long product = combineTwoNumbers(a, b, (p1, p2) -> p1 * p2);
        System.out.println("Sum is " + sum);
        System.out.println("Product is " + product);
    }

    public static Long combineTwoNumbers(Long a, Long b, BiFunction <Long, Long, Long> combiner) {
        return combiner.apply(a, b);
    }
}

Here, the functional parameter is BiFunction, which takes two parameters in input and returns an output. Specifically, it takes two long numbers and produces a third one as a result. The name of the method is kept generic so that it can cover more instances of different functions that may take place. In our example we are passing a sum and a product function as you can see.

NiVeR
  • 9,644
  • 4
  • 30
  • 35