2017-08-16 208 views
0

我一直在看的java FunctionalInterface java.util.function.Consumer具有源代碼java.util.function.Consumer andThen方法有效存儲器使用

package java.util.function; 
import java.util.Objects; 

public interface Consumer<T> { 
    void accept(T t); 

    default Consumer<T> andThen(Consumer<? super T> after) { 
     Objects.requireNonNull(after); 
     return (T t) -> { accept(t); after.accept(t); }; 
    } 

} 

所以如果我打電話consumer1.andThen(consumer2) ...和Then(consumerN).accept(); 在我看來,這有效地創造了消費者對象的N +(N-1)。請讓我知道,如果我用錯了,或者我不應該這樣使用它。

這是我的測試代碼來測試問題。我錯過了什麼?

public class Test1 { 
    public static int c = 0; 

    public static int acceptC = 0; 

    public Test1(){ 
     ++c; 
     System.out.println("new Object Created = "+c); 
    } 

    public void accept(int i){ 
     acceptC++; 
     System.out.println("accept call "+ acceptC); 
    } 

    public Test1 andThen(Test1 after) { 
     return new Test1(){ 
     @Override 
     public void accept(int i) { 
      acceptC++; 
      System.out.println("accept call in temp = " +acceptC) ; 
      Test1.this.accept(++i); after.accept(++i); 
     } 

     }; 
    } 

    public static void main(String args[]){ 
     Test1 t1 = new Test1(); 
     Test1 t2 = new Test1(); 
     Test1 t3 = new Test1(); 
     Test1 t4 = new Test1(); 
     Test1 t5 = new Test1(); 

     t1.andThen(t2).andThen(t3).andThen(t4).andThen(t5).accept(0); 
     System.out.println("RESULT total Test Object created ="+Test1.c); 
    } 
} 

我得到的輸出將

new Object Created = 1 
new Object Created = 2 
new Object Created = 3 
new Object Created = 4 
new Object Created = 5 
new Object Created = 6 
new Object Created = 7 
new Object Created = 8 
new Object Created = 9 
accept call in temp = 1 
accept call in temp = 2 
accept call in temp = 3 
accept call in temp = 4 
accept call 5 
accept call 6 
accept call 7 
accept call 8 
accept call 9 
RESULT total Test Object created =9 

我知道,除非你正在處理大量數據的方式.. 這並不重要了很多,但只是想知道

回答

0

它故意未指定在評估函數接口的實例的lambda表達式時是否創建新對象,另請參見Does a lambda expression create an object on the heap every time it's executed?

因此,我們無法就此操作創建的對象實例的數量進行一般性說明,特別是對於可能存在可重用實例的相同代碼的重複執行情況(並且這可能很重要) 。此外,Consumer.andThen的確切實現不是固定的,不必看起來像發佈的代碼。 default方法可覆蓋也很重要,因此如果您打電話andThen的第一個Consumer不是lambda表達式的結果,而是自定義實現的結果,則可能會顯着改變整個結果。

實際上,當前實現,lambda表達式(T t) -> { accept(t); after.accept(t); }將捕獲兩個引用其他Consumer實例,因此評估一個新Consumer實例每次,就像你的具體類的變體。因此,調用andThen這個鏈將創建一個Consumer實例的不平衡樹,就像您的變體一樣。

但是,這並不意味着所有葉子消費者實例都將是新實例。在你的例子中,所有的葉函數的形式爲​​,這意味着要捕獲this才能修改acceptC,所以等價的lambda表達式將每次計算新實例。但這不是真實的生活場景。在實踐中,你會使用andThen來結合不同的消費者,所以其中一些可能捕獲,其他可能不捕獲,因此其中一些可能被重用,而另一些則可能被重用。

這就是目前的實現。未來的實現可能會將不同但相同的lambda表達式摺疊爲單個實例,或者識別lambda表達式何時僅捕獲對可重用lambda實例的引用以使其可重用。這可能會產生級聯效應,極大地減少了實例的數量。

你說你已經意識到對象的數量並不重要。但值得注意的是,過度使用andThen會產生深度不平衡的消費者樹,其執行方法可能需要大量的堆棧深度。