具有不兼容参数的Java 8 Lambda转换

mer*_*nan 2 lambda java-8 functional-interface

import org.junit.Test;

import java.util.stream.IntStream;

public class GomanTest {

    @Test
    public void someTest() {
        IntStream.of(2, 3, 1).collect(Container::new, Container::add, null);
    }
}


class Container<T> {

    void add(T t) {
        System.out.println("this is container " + t);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

this is container 2
this is container 3
this is container 1
Run Code Online (Sandbox Code Playgroud)

这在1.8.0_45.jdk上成功运行.Container#add如何被翻译成ObjIntConsumer #accept?

Hol*_*ger 6

该方法Container.add是一个实例方法,需要调用实例.由于表单上的方法引用ClassName::methodName未绑定到实例,Container::add因此具有函数签名(Container<T>,T).

由于您没有为Container目标类型指定类型参数,编译器将推断Container<Object>.因此Container::add有推测签名(Container<Object>,Object)在这里,这是适合accept的方法ObjIntConsumer<Container<Object>>,其中有签名(Container<Object>,int).

第二个参数可以接受类型的值int,因为,在将其装箱后Integer,它可以赋值给Object.

如果将结果分配给变量,从而提供目标类型Container<Object>Container<Integer>类似,则同样有效

Container<Integer> collected
   = IntStream.of(2, 3, 1).collect(Container::new, Container::add, null);
Run Code Online (Sandbox Code Playgroud)

任何可以使用的类型参数Integer,例如Serializable或者也可以使用Number.


您可以在"Java 8中的特定类型的任意对象是什么意思?"中阅读有关实例方法的无界引用的更多信息.


作为旁注,collect流的方法不应该接受null参数而Stream实现不会.传递null与原始流一起工作是当前实现中的一个小故障,并且通过的代码null很可能在下一个版本中中断.正如Tagir Valeev指出的那样,Java 9当前的开发状态已经发生了变化.

  • 顺便说一句,我很惊讶`IntStream`接受`null`作为`collect`的最后一个参数.标准的`Stream`实现没有. (4认同)
  • 在JDK-9中已经[已经修复](http://hg.openjdk.java.net/jdk9/dev/jdk/diff/013baa71b58b/src/share/classes/java/util/stream/IntPipeline.java)我不会这样写 (3认同)