What's the nearest substitute for a function pointer in Java?

前端 未结 22 1542
太阳男子
太阳男子 2020-11-22 15:32

I have a method that\'s about ten lines of code. I want to create more methods that do exactly the same thing, except for a small calculation that\'s going to change one li

相关标签:
22条回答
  • 2020-11-22 16:18

    If you have just one line which is different you could add a parameter such as a flag and a if(flag) statement which calls one line or the other.

    0 讨论(0)
  • 2020-11-22 16:19

    The open source safety-mirror project generalizes some of the above mentioned solutions into a library that adds functions, delegates and events to Java.

    See the README, or this stackoverflow answer, for a cheat sheet of features.

    As for functions, the library introduces a Fun interface, and some sub-interfaces that (together with generics) make up a fluent API for using methods as types.

    Fun.With0Params<String> myFunctionField = "   hello world   "::trim;`  
    Fun.With2Params<Boolean, Object, Object> equals = Objects::equals;`  
        
    public void foo(Fun.With1ParamAndVoid<String> printer) throws Exception {
        printer.invoke("hello world);
    }  
    
    public void test(){
        foo(System.out::println);
    }  
    

    Notice:

    1. that you must choose the sub-interface that matches the number of parameters in the signature you are targeting. Fx, if it has one parameter, choose Fun.With1Param.
    2. that Generics are used to define A) the return type and B) the parameters of the signature.

    Also, notice that the signature of the Method Reference passed to the call to the foo() method must match the the Fun defined by method Foo. If it do not, the compiler will emit an error.

    0 讨论(0)
  • 2020-11-22 16:20

    If anyone is struggling to pass a function that takes one set of parameters to define its behavior but another set of parameters on which to execute, like Scheme's:

    (define (function scalar1 scalar2)
      (lambda (x) (* x scalar1 scalar2)))
    

    see Pass Function with Parameter-Defined Behavior in Java

    0 讨论(0)
  • 2020-11-22 16:22

    The Google Guava libraries, which are becoming very popular, have a generic Function and Predicate object that they have worked into many parts of their API.

    0 讨论(0)
  • 2020-11-22 16:26

    You need to create an interface that provides the function(s) that you want to pass around. eg:

    /**
     * A simple interface to wrap up a function of one argument.
     * 
     * @author rcreswick
     *
     */
    public interface Function1<S, T> {
    
       /**
        * Evaluates this function on it's arguments.
        * 
        * @param a The first argument.
        * @return The result.
        */
       public S eval(T a);
    
    }
    

    Then, when you need to pass a function, you can implement that interface:

    List<Integer> result = CollectionUtilities.map(list,
            new Function1<Integer, Integer>() {
               @Override
               public Integer eval(Integer a) {
                  return a * a;
               }
            });
    

    Finally, the map function uses the passed in Function1 as follows:

       public static <K,R,S,T> Map<K, R> zipWith(Function2<R,S,T> fn, 
             Map<K, S> m1, Map<K, T> m2, Map<K, R> results){
          Set<K> keySet = new HashSet<K>();
          keySet.addAll(m1.keySet());
          keySet.addAll(m2.keySet());
    
          results.clear();
    
          for (K key : keySet) {
             results.put(key, fn.eval(m1.get(key), m2.get(key)));
          }
          return results;
       }
    

    You can often use Runnable instead of your own interface if you don't need to pass in parameters, or you can use various other techniques to make the param count less "fixed" but it's usually a trade-off with type safety. (Or you can override the constructor for your function object to pass in the params that way.. there are lots of approaches, and some work better in certain circumstances.)

    0 讨论(0)
  • 2020-11-22 16:26

    oK, this thread is already old enough, so very probably my answer is not helpful for the question. But since this thread helped me to find my solution, I'll put it out here anyway.

    I needed to use a variable static method with known input and known output (both double). So then, knowing the method package and name, I could work as follows:

    java.lang.reflect.Method Function = Class.forName(String classPath).getMethod(String method, Class[] params);
    

    for a function that accepts one double as a parameter.

    So, in my concrete situation I initialized it with

    java.lang.reflect.Method Function = Class.forName("be.qan.NN.ActivationFunctions").getMethod("sigmoid", double.class);
    

    and invoked it later in a more complex situation with

    return (java.lang.Double)this.Function.invoke(null, args);
    
    java.lang.Object[] args = new java.lang.Object[] {activity};
    someOtherFunction() + 234 + (java.lang.Double)Function.invoke(null, args);
    

    where activity is an arbitrary double value. I am thinking of maybe doing this a bit more abstract and generalizing it, as SoftwareMonkey has done, but currently I am happy enough with the way it is. Three lines of code, no classes and interfaces necessary, that's not too bad.

    0 讨论(0)
提交回复
热议问题