【问题标题】:High Order Functions in JavaJava中的高阶函数
【发布时间】:2015-03-13 20:50:18
【问题描述】:

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

【问题讨论】:

  • IMO 如果你给出一个实际或假设的例子,这将是一个更好的问题。否则,这是一个基于情况的相当广泛的问题。最好的办法是查看 Javadocs,尝试这样做时不会遇到特定问题。
  • 我正在做一个库,我想允许用户传递错误回调。
  • @makoto 链接的问题没有显示定义接收函数的方法。你不应该这么快就关闭它。

标签: java function


【解决方案1】:

是的。查看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&lt;? super T&gt; 类型的消费者函数,在本例中是来自Collection&lt;E&gt;List&lt;T&gt; 实现)的add 方法。因此,您基本上已经将一个方法作为参数传递给另一个方法。

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

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,并从ConsoleErrorHandler 的实例引用handleError

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

您甚至可以使用 lambda 临时执行此操作:

doSomething("Something", (ErrorResult result) -> {
    System.out.println(result.getErrorMessage()); 
});

请注意,由于泛型,您会获得编译时类型检查,因此您不能简单地将接受单个参数的任何方法传递给doSomething

【讨论】:

  • 谢谢维文。很有帮助。
  • @VivinPaliath,当它只是一个链接时,我投了反对票,然后你删除了它,或者它出现了,现在我把它收回并给了一个。
【解决方案2】:

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&lt;T&gt;

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

我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    相关资源
    最近更新 更多