Java lambda 返回一个 lambda [英] Java lambda returning a lambda

查看:17
本文介绍了Java lambda 返回一个 lambda的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在新的 JDK 8 函数式编程领域中做一些看似相对基本的事情,但我无法让它工作.我有这个工作代码:

I am trying to do what seems to be a relatively basic thing in the new JDK 8 land of functional programming, but I can't get it to work. I have this working code:

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;

public class so1 {
   public static void main() {
      List<Number> l = new ArrayList<>(Arrays.asList(1, 2, 3));
      List<Callable<Object>> checks = l.stream().
               map(n -> (Callable<Object>) () -> {
                  System.out.println(n);
                  return null;
               }).
               collect(Collectors.toList());
   }
}

它需要一个数字列表并生成一个可以打印出来的函数列表.但是,对 Callable 的显式转换似乎是多余的.在我和 IntelliJ 看来.我们都同意这也应该有效:

It takes a list of numbers and produces a list of functions that can print them out. However, the explicit cast to Callable seems redundant. It seems to me and to IntelliJ. And we both agree that this should also work:

List<Callable<Object>> checks = l.stream().
       map(n -> () -> {
          System.out.println(n);
          return null;
       }).
       collect(Collectors.toList());

但是我得到一个错误:

so1.java:10: error: incompatible types: cannot infer type-variable(s) R
      List<Callable<Object>> checks = l.stream().map(n -> () -> {System.out.println(n); return null;}).collect(Collectors.toList());
                                                    ^
    (argument mismatch; bad return type in lambda expression
      Object is not a functional interface)
  where R,T are type-variables:
    R extends Object declared in method <R>map(Function<? super T,? extends R>)
    T extends Object declared in interface Stream
1 error

推荐答案

您遇到了 Java 8 目标类型的限制,该限制适用于方法调用的接收者.虽然目标类型(大多数情况下)适用于参数类型,但它不适用于调用方法的对象或表达式.

You hit a limitation of Java 8’s target typing which applies to the receiver of a method invocation. While target typing works (most of the times) for parameter types it does not work for the object or expression on which you invoke the method.

这里,l.stream().地图(n -> () -> {System.out.println(n);返回空;})collect(Collectors.toList()) 方法调用的接收者,所以目标类型 List> 不是考虑过.

Here, l.stream(). map(n -> () -> { System.out.println(n); return null; }) is the receiver of the collect(Collectors.toList()) method invocation, so the target type List<Callable<Object>> is not considered for it.

如果目标类型已知,很容易证明嵌套的 lambda 表达式有效,例如

It’s easy to prove that nested lambda expressions work if the target type is know, e.g.

static <T> Function<T,Callable<Object>> toCallable() {
    return n -> () -> {
        System.out.println(n); 
        return null;
    };
}

工作没有问题,你可以用它来解决你原来的问题

works without problems and you can use it to solve your original problem as

List<Callable<Object>> checks = l.stream()
    .map(toCallable()).collect(Collectors.toList());

你也可以通过引入一个辅助方法来解决这个问题,该方法将第一个表达式的角色从方法接收者变成了一个参数

You can also solve the problem by introducing a helper method which changes the role of the first expression from method receiver to a parameter

// turns the Stream s from receiver to a parameter
static <T, R, A> R collect(Stream<T> s, Collector<? super T, A, R> collector) {
    return s.collect(collector);
}

并将原来的表达式改写为

and rewrite the original expression as

List<Callable<Object>> checks = collect(l.stream().map(
    n -> () -> {
        System.out.println(n); 
        return null;
    }), Collectors.toList());

这不会降低代码的复杂性,但可以毫无问题地编译.对我来说,这是一种似曾相识的感觉.当 Java 5 和泛型问世时,程序员不得不在 new 表达式上重复类型参数,而简单地将表达式包装到泛型方法中证明推断类型没有问题.直到 Java 7 才允许程序员省略这些不必要的类型参数重复(使用菱形运算符").现在我们遇到了类似的情况,把一个调用表达式包装成另一个方法,把接收者变成一个参数,证明这个限制是没有必要的.所以也许我们在 Java 10 中摆脱了这个限制......

This does not reduce the complexity of the code but can be compiled without any problems. For me, it’s a déjà vu. When Java 5 and Generics came out, programmers had to repeat the type parameters on new expressions while simply wrapping the expression into a generic method proved that inferring the type is no problem. It took until Java 7 before programmers were allowed to omit these unnecessary repetition of the type arguments (using the "diamond operator"). Now we have a similar situation, wrapping an invocation expression into another method, turning the receiver into a parameter, proves that this limitation is unnecessary. So maybe we get rid of this limitation in Java 10…

这篇关于Java lambda 返回一个 lambda的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆