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

前端 未结 22 1552
太阳男子
太阳男子 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:09

    When there is a predefined number of different calculations you can do in that one line, using an enum is a quick, yet clear way to implement a strategy pattern.

    public enum Operation {
        PLUS {
            public double calc(double a, double b) {
                return a + b;
            }
        },
        TIMES {
            public double calc(double a, double b) {
                return a * b;
            }
        }
         ...
    
         public abstract double calc(double a, double b);
    }
    

    Obviously, the strategy method declaration, as well as exactly one instance of each implementation are all defined in a single class/file.

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

    @sblundy's answer is great, but anonymous inner classes have two small flaws, the primary being that they tend not to be reusable and the secondary is a bulky syntax.

    The nice thing is that his pattern expands into full classes without any change in the main class (the one performing the calculations).

    When you instantiate a new class you can pass parameters into that class which can act as constants in your equation--so if one of your inner classes look like this:

    f(x,y)=x*y
    

    but sometimes you need one that is:

    f(x,y)=x*y*2
    

    and maybe a third that is:

    f(x,y)=x*y/2
    

    rather than making two anonymous inner classes or adding a "passthrough" parameter, you can make a single ACTUAL class that you instantiate as:

    InnerFunc f=new InnerFunc(1.0);// for the first
    calculateUsing(f);
    f=new InnerFunc(2.0);// for the second
    calculateUsing(f);
    f=new InnerFunc(0.5);// for the third
    calculateUsing(f);
    

    It would simply store the constant in the class and use it in the method specified in the interface.

    In fact, if KNOW that your function won't be stored/reused, you could do this:

    InnerFunc f=new InnerFunc(1.0);// for the first
    calculateUsing(f);
    f.setConstant(2.0);
    calculateUsing(f);
    f.setConstant(0.5);
    calculateUsing(f);
    

    But immutable classes are safer--I can't come up with a justification to make a class like this mutable.

    I really only post this because I cringe whenever I hear anonymous inner class--I've seen a lot of redundant code that was "Required" because the first thing the programmer did was go anonymous when he should have used an actual class and never rethought his decision.

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

    You can also do this (which in some RARE occasions makes sense). The issue (and it is a big issue) is that you lose all the typesafety of using a class/interface and you have to deal with the case where the method does not exist.

    It does have the "benefit" that you can ignore access restrictions and call private methods (not shown in the example, but you can call methods that the compiler would normally not let you call).

    Again, it is a rare case that this makes sense, but on those occasions it is a nice tool to have.

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    class Main
    {
        public static void main(final String[] argv)
            throws NoSuchMethodException,
                   IllegalAccessException,
                   IllegalArgumentException,
                   InvocationTargetException
        {
            final String methodName;
            final Method method;
            final Main   main;
    
            main = new Main();
    
            if(argv.length == 0)
            {
                methodName = "foo";
            }
            else
            {
                methodName = "bar";
            }
    
            method = Main.class.getDeclaredMethod(methodName, int.class);
    
            main.car(method, 42);
        }
    
        private void foo(final int x)
        {
            System.out.println("foo: " + x);
        }
    
        private void bar(final int x)
        {
            System.out.println("bar: " + x);
        }
    
        private void car(final Method method,
                         final int    val)
            throws IllegalAccessException,
                   IllegalArgumentException,
                   InvocationTargetException
        {
            method.invoke(this, val);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 16:10

    Wow, why not just create a Delegate class which is not all that hard given that I already did for java and use it to pass in parameter where T is return type. I am sorry but as a C++/C# programmer in general just learning java, I need function pointers because they are very handy. If you are familiar with any class which deals with Method Information you can do it. In java libraries that would be java.lang.reflect.method.

    If you always use an interface, you always have to implement it. In eventhandling there really isn't a better way around registering/unregistering from the list of handlers but for delegates where you need to pass in functions and not the value type, making a delegate class to handle it for outclasses an interface.

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

    Anonymous inner class

    Say you want to have a function passed in with a String param that returns an int.
    First you have to define an interface with the function as its only member, if you can't reuse an existing one.

    interface StringFunction {
        int func(String param);
    }
    

    A method that takes the pointer would just accept StringFunction instance like so:

    public void takingMethod(StringFunction sf) {
       int i = sf.func("my string");
       // do whatever ...
    }
    

    And would be called like so:

    ref.takingMethod(new StringFunction() {
        public int func(String param) {
            // body
        }
    });
    

    EDIT: In Java 8, you could call it with a lambda expression:

    ref.takingMethod(param -> bodyExpression);
    
    0 讨论(0)
  • 2020-11-22 16:13

    For each "function pointer", I'd create a small functor class that implements your calculation. Define an interface that all the classes will implement, and pass instances of those objects into your larger function. This is a combination of the "command pattern", and "strategy pattern".

    @sblundy's example is good.

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