2015-09-15 49 views
2
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); 
    } 
} 

輸出:的Java 8 LAMBDA翻譯與incompatiable參數

this is container 2 
this is container 3 
this is container 1 

這成功地運行在1.8.0_45.jdk。 Container#add如何被轉換爲ObjIntConsumer#accept?

回答

6

方法Container.add是需要調用實例的實例方法。由於形式爲ClassName::methodName的方法引用未綁定到實例,因此Container::add的功能簽名爲(Container<T>,T)

由於您沒有爲Container指定類型參數,也沒有指定目標類型,因此編譯器會推斷出Container<Object>。所以Container::add在這裏具有推斷的簽名(Container<Object>,Object),這適用於方法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); 

任何類型的參數,它可以消耗的Integer,例如SerializableNumber,也可以工作。


你可以閱讀更多關於「What does ‘an Arbitrary Object of a Particular Type’ mean in java 8?」以實例方法無界引用。


作爲一個側面說明,流的collect方法不應該接受null參數和Stream實現沒有。通過null與原始流一起工作是當前實現中的一個小故障,通過null的代碼有可能在下一個版本中破解。作爲Tagir Valeev pointed out,在Java 9的當前開發狀態​​下,行爲已經是changed

+4

順便說一句,我很驚訝'IntStream'接受'null'作爲'collect'的最後一個參數。標準的'Stream'實現沒有。 – Holger

+3

JDK-9中的[已經修復](http://hg.openjdk.java.net/jdk9/dev/jdk/diff/013baa71b58b/src/share/classes/java/util/stream/IntPipeline.java)因此我不會這樣寫 –

+0

我的困惑不在於拳擊,拆箱。我提供了一個參數「add(T t)」的方法,但是它被轉換爲2個參數accept(T t,int value)。我期望的是這樣的: required:java.lang.Integer found:java.lang.Integer,int reason:實際和形式參數列表的長度不同 –