How can I pass a generic java function as a parameter?

338    Asked by manishJhadav in Java , Asked on Oct 11, 2022

Ran into this idea and I'm curious if it's possible.

I'm trying to make a single function that can test ALL of my sorting algorithms dynamically. I want to be able to pass the sorting function as a parameter and the algorithm will use the sorting function with its own dynamic parameters. This is an example of what I'm trying to do:

class manyFunctions{
    int[] mergeSort(int[] myArray){
        ...work here;
        return sortedArray;
    }
    int[] otherSort(int[] myArray){
        ...work here;
        return sortedArray;
        }
}
class mainClass{
   public static void main(String[]Args){
      test(manyFunctions.mergeSort);
      test(manyFunctions.otherSort);
   }
 boolean test(function someSortFunction){
        int n; // number of trials
        for (int i=0; i<=n ; i++) {
        int[] A = generateArray() // another function I made
            if (isSorted(someSortFunction(A)) = false) {
                return false;
            }
        }
     return true;
 }

I can't figure out how to do this with the little bit I know about lambda expressions and function pointers. If it's possible, this technique would come in handy.


Answered by Manish Nagar

Regarding passing the Java function as parameter, your test function is wrong in multiple places:


boolean test(function someSortFunction){//This is not how you pass functions

    int n; //this has to be initialised

    for (int i=0; i<=n ; i++) {//Depending on how n is used, you may have to use < instead xss=removed>

        int[] A = generateArray()//Missing semicolon
        if (isSorted(someSortFunction(A)) = false) {//Comparing is done with ==, not =
            return false;
        }
    }
    return true;
}

In order to pass a function, you can either use Consumer, Supplier, Predicate or Function (don't use Void as the type if you have return values)

Supplier defines return type, Consumer defines input type, and function both. Meaning:

Use Predicate when you have a boolean return type with arguments

Use Supplier when you have a return type

Use Consumer when you have an argument

Use Function when you have both an argument and a return value

Since you have both arguments and return types, use Function. The first argument you give it is the argument it receives, and the second is the return type. For an instance, in your case, this would be:

boolean test(Function someFunction)

Using Function requires calling apply to execute the method:

int[] res = someFunction.apply(input);

Before I move on, I'd like to take a second to mention naming conventions. In Java, class names always start with an uppercase letter. Instances and functions start with a lowercase letter. So your classes would be:

public class ManyFunctions {...}

public class MainClass {...}

Passing methods are not done using someClass.someFunction. In your case, since you are not using static methods, you need to create an instance:

ManyFunctions functions = new ManyFunctions();

now, you pass the functions:

test(functions::mergeSort);

if you make the methods static, you can just skip the instance and use the class name directly:

test(ManyFunctions::mergeSort);

So your class would be:

class MainClass{

    public static void main(String[] args){

        ManyFunctions manyFunctions = new ManyFunctions();

        test(manyFunctions::mergeSort);//Notice the missing "()" and arguments

        test(manyFunctionsNote: This answer is based on Java 8 and newer. This does not apply to Java 7, as Java 7 does not support Lambda

For starters, your test function is wrong in multiple places:

boolean test(function someSortFunction){//This is not how you pass functions

    int n; //this has to be initialised

    for (int i=0; i<=n ; i++) {//Depending on how n is used, you may have to use < instead xss=removed>

        int[] A = generateArray()//Missing semicolon

        if (isSorted(someSortFunction(A)) = false) {//Comparing is done with ==, not =

            return false;

        }

    }

    return true;

}

In order to pass a function, you can either use Consumer, Supplier, Predicate or Function (don't use Void as the type if you have return values)

Supplier defines return type, Consumer defines input type, and function both. Meaning:

Use Predicate when you have a boolean return type with arguments

Use Supplier when you have a return type

Use Consumer when you have an argument

Use Function when you have both an argument and a return value

Since you have both arguments and return types, use Function. The first argument you give it is the argument it receives, and the second is the return type. For an instance, in your case, this would be:

boolean test(Function someFunction)

Using Function requires calling apply to execute the method:

int[] res = someFunction.apply(input);

Before I move on, I'd like to take a second to mention naming conventions. In Java, class names always start with an uppercase letter. Instances and functions start with a lowercase letter. So your classes would be:

public class ManyFunctions {...}

public class MainClass {...}

Passing methods are not done using someClass.someFunction. In your case, since you are not using static methods, you need to create an instance:

ManyFunctions functions = new ManyFunctions();

now, you pass the functions:

test(functions::mergeSort);

if you make the methods static, you can just skip the instance and use the class name directly:

test(ManyFunctions::mergeSort);

So your class would be:
class MainClass{
    public static void main(String[] args){
        ManyFunctions manyFunctions = new ManyFunctions();
        test(manyFunctions::mergeSort);//Notice the missing "()" and arguments
        test(manyFunctions::otherSort);
    }
    boolean test(Function someSortFunction){
        int n = 10;//THIS HAS TO BE INITIALISED! Otherwise, it won't compile
        for (int i=0; i<=n ; i++) {
            int[] A = generateArray();
            if (isSorted(someSortFunction.apply(A)) == false) {//comparing is done with ==
                return false;
            }
         }
         return true;
    }

}//Don't know if it was a copy-paste problem or not, but you had a missing bracket.



Your Answer