What's the nearest substitute for a function p

2018-12-31 17:07发布

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 line of code. This is a perfect application for passing in a function pointer to replace that one line, but Java doesn't have function pointers. What's my best alternative?

21条回答
怪性笑人.
2楼-- · 2018-12-31 17:38

Method references using the :: operator

You can use method references in method arguments where the method accepts a functional interface. A functional interface is any interface that contains only one abstract method. (A functional interface may contain one or more default methods or static methods.)

IntBinaryOperator is a functional interface. Its abstract method, applyAsInt, accepts two ints as its parameters and returns an int. Math.max also accepts two ints and returns an int. In this example, A.method(Math::max); makes parameter.applyAsInt send its two input values to Math.max and return the result of that Math.max.

import java.util.function.IntBinaryOperator;

class A {
    static void method(IntBinaryOperator parameter) {
        int i = parameter.applyAsInt(7315, 89163);
        System.out.println(i);
    }
}
import java.lang.Math;

class B {
    public static void main(String[] args) {
        A.method(Math::max);
    }
}

In general, you can use:

method1(Class1::method2);

instead of:

method1((arg1, arg2) -> Class1.method2(arg1, arg2));

which is short for:

method1(new Interface1() {
    int method1(int arg1, int arg2) {
        return Class1.method2(arg1, agr2);
    }
});

For more information, see :: (double colon) operator in Java 8 and Java Language Specification §15.13.

查看更多
君临天下
3楼-- · 2018-12-31 17:38

New Java 8 Functional Interfaces and Method References using the :: operator.

Java 8 is able to maintain method references ( MyClass::new ) with "@ Functional Interface" pointers. There are no need for same method name, only same method signature required.

Example:

@FunctionalInterface
interface CallbackHandler{
    public void onClick();
}

public class MyClass{
    public void doClick1(){System.out.println("doClick1");;}
    public void doClick2(){System.out.println("doClick2");}
    public CallbackHandler mClickListener = this::doClick;

    public static void main(String[] args) {
        MyClass myObjectInstance = new MyClass();
        CallbackHandler pointer = myObjectInstance::doClick1;
        Runnable pointer2 = myObjectInstance::doClick2;
        pointer.onClick();
        pointer2.run();
    }
}

So, what we have here?

  1. Functional Interface - this is interface, annotated or not with @FunctionalInterface, which contains only one method declaration.
  2. Method References - this is just special syntax, looks like this, objectInstance::methodName, nothing more nothing less.
  3. Usage example - just an assignment operator and then interface method call.

YOU SHOULD USE FUNCTIONAL INTERFACES FOR LISTENERS ONLY AND ONLY FOR THAT!

Because all other such function pointers are really bad for code readability and for ability to understand. However, direct method references sometimes come handy, with foreach for example.

There are several predefined Functional Interfaces:

Runnable              -> void run( );
Supplier<T>           -> T get( );
Consumer<T>           -> void accept(T);
Predicate<T>          -> boolean test(T);
UnaryOperator<T>      -> T apply(T);
BinaryOperator<T,U,R> -> R apply(T, U);
Function<T,R>         -> R apply(T);
BiFunction<T,U,R>     -> R apply(T, U);
//... and some more of it ...
Callable<V>           -> V call() throws Exception;
Readable              -> int read(CharBuffer) throws IOException;
AutoCloseable         -> void close() throws Exception;
Iterable<T>           -> Iterator<T> iterator();
Comparable<T>         -> int compareTo(T);
Comparator<T>         -> int compare(T,T);

For earlier Java versions you should try Guava Libraries, which has similar functionality, and syntax, as Adrian Petrescu has mentioned above.

For additional research look at Java 8 Cheatsheet

and thanks to The Guy with The Hat for the Java Language Specification §15.13 link.

查看更多
还给你的自由
4楼-- · 2018-12-31 17:41

Prior to Java 8, nearest substitute for function-pointer-like functionality was an anonymous class. For example:

Collections.sort(list, new Comparator<CustomClass>(){
    public int compare(CustomClass a, CustomClass b)
    {
        // Logic to compare objects of class CustomClass which returns int as per contract.
    }
});

But now in Java 8 we have a very neat alternative known as lambda expression, which can be used as:

list.sort((a, b) ->  { a.isBiggerThan(b) } );

where isBiggerThan is a method in CustomClass. We can also use method references here:

list.sort(MyClass::isBiggerThan);
查看更多
皆成旧梦
5楼-- · 2018-12-31 17:43

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);
查看更多
怪性笑人.
6楼-- · 2018-12-31 17:43

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.

查看更多
浅入江南
7楼-- · 2018-12-31 17:48
登录 后发表回答