Java中的高阶函数

时间:2015-03-13 20:50:18

标签: java function

我想知道是否有办法将函数作为参数传递给方法。无论如何我在Java 8中可以做到这一点吗?请彻底解释我必须采取的步骤,并提前感谢您。

2 个答案:

答案 0 :(得分:8)

是。查看java.util.function包,了解可以使用的不同类型的功能接口。

您可能想要的是Function<T, R>,它是一个函数的签名,它接受类型T的单个参数并返回类型R的值。对于更具体的案例,还有其他接口。例如,让我们说你想要某种谓词。然后,您可以使用Predicate<T>来描述您希望接受一个方法,该方法根据对T类型值的某种解释来返回布尔值。

这就是许多方法在流上工作的方式。例如,Stream<T>中的forEach是一个接受Consumer<? super T>类型参数的方法。这基本上是一个函数,它接受一个参数并用它做一些事情。

就传递函数本身而言,您可以使用method references或通过lambdas创建功能接口的临时实现。

这是一个人为的例子,我在地图上迭代并将所有值添加到列表中:

List<Integer> list = new ArrayList<>();
Map<String, Integer> map = fromSomeMethod();

map.values().stream().forEach(list::add);

此处forEach接受Consumer<? super T>类型的消费者功能,在这种情况下是来自add的{​​{1}}方法(Collection<E>实现)。List<T>因此,您基本上将一个方法作为参数传递给另一个方法。

这是我使用相同方法的另一个例子,但这次我打印出列表中的元素:

list.stream().forEach(System.out::println);

使用此方法,您可以创建接受其他方法的自己的方法,它就像定义java.util.function中定义的任何一种类型的参数一样简单。对于您的错误回调案例,您可以执行以下操作:

public void doSomething(String something, Consumer<ErrorResult> errorHandler) {

    //do some stuff
    if(errorHappened) {
        //call the error handler with a new ErrorResult object
        errorHandler.accept(new ErrorResult(...)); 
    }
}

然后让我们说你有一个方法只是在某个类中打印出错误结果

public class ConsoleErrorHandler {
    public void handleError(ErrorResult result) {
        System.out.println(result.getErrorMessage());
    }
}

现在,您可以从doSomething的实例引用handleError来调用ConsoleErrorHandler

ConsoleErrorHandler handler = new ConsoleErrorHandler();
doSomething("Something", handler::handleError);

您甚至可以使用lambda:

临时执行此操作
doSomething("Something", (ErrorResult result) -> {
    System.out.println(result.getErrorMessage()); 
});

请注意,由于泛型,您需要进行编译时类型检查,这样您就不能简单地将接受单个参数的任何方法传递到doSomething

答案 1 :(得分:3)

Java中没有函数类型,因此您必须使用单个方法接口。

java.util.function定义了很多,但是可以使用任何具有单个方法的接口。

例如:

// An interface with a single method that return 
// something of type T
interface F<T> {
    T doSomething();
}
class A {
    // This method expect an instance of the interface F
    private static String f( F<String> x ) {
        // and then invokes its only method.
        return x.doSomething();
    }

     // Test it
    public static void main( String ... args ) {
        //Call the method f using a 
        // this function literal: ()-> "hola"
        System.out.println(
            f( () -> "hola" )
        );
    }
}

函数文字:

() -> "hola"

隐含地满足界面F<T>

总之,您可以将类型指定为具有单个方法(任何接口)的接口。如果您使用java.util.function包中的一个现有接口,那就更好了。

我希望这会有所帮助。