2017-08-16 4 views
0

I wurde auf Java FunctionalInterface java.util.function.Consumer suchen, die den Quellcodejava.util.function.Consumer andthen Methode effektive Speichernutzung

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); }; 
    } 

} 

so, wenn ich consumer1.andThen (Consumer2) nennen ... und dann (consumerN) .accept(); es scheint mir, dass dies effektiv N + (N - 1) von Consumer Objects erstellt. Bitte lassen Sie es mich wissen, wenn ich es falsch benutze oder sollte ich es nicht so benutzen.

Hier ist mein Testcode, um das Problem zu testen. Fehle ich etwas?

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); 
    } 
} 

ich die Put Out

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 

Ich weiß, dass dies nicht viel ist egal, wenn Sie eine viel Daten verarbeiten auf diese Weise .. aber wollte nur

Antwort

0

wissen es ist absichtlich nicht spezifiziert, ob bei der Auswertung eines Lambda-Ausdrucks zu einer Instanz einer funktionalen Schnittstelle ein neues Objekt erzeugt wird, siehe auch Does a lambda expression create an object on the heap every time it's executed?.

Daher können wir keine allgemeine Aussage über die Anzahl der für diesen Vorgang erstellten Objektinstanzen machen, insbesondere für wiederholte Ausführungen desselben Codes, wo möglicherweise wiederbenutzbare Instanzen existieren (und das ist das Szenario, wo es wichtig sein könnte) . Außerdem ist die genaue Implementierung von Consumer.andThen nicht festgelegt und muss nicht wie der veröffentlichte Code aussehen. Es ist auch wichtig, dass default Methoden überschreibbar sind, also wenn das erste Consumer Sie andThen on aufrufen, ist nicht das Ergebnis eines Lambda-Ausdrucks, sondern eine benutzerdefinierte Implementierung, es könnte das gesamte Ergebnis dramatisch ändern.

Praktisch mit der aktuellen Implementierung, der Lambda-Ausdruck (T t) -> { accept(t); after.accept(t); } erfassen wird zwei Verweise auf andere Consumer Instanzen und damit zu einer neuen Consumer Instanz jedes Mal, genau wie bei Ihrer konkreten Klasse Variante bewerten. Also diese Kette von andThen Anrufe erstellen einen unausgeglichenen Baum von Consumer Instanzen, wie in Ihrer Variante.

Dies bedeutet jedoch nicht, dass alle Benutzer von Leaf-Consumer-Instanzen neue Instanzen sein werden. In Ihrem Beispiel haben alle Blattfunktionen die Form acceptC++; System.out.println("accept call "+ acceptC);, was bedeuten würde, dass this abgefangen würde, um acceptC zu modifizieren, so dass ein äquivalenter Lambda-Ausdruck jedes Mal zu neuen Instanzen ausgewertet würde. Aber das ist kein echtes Lebensszenario. In der Praxis würden Sie andThen verwenden, um verschiedene Konsumenten zu kombinieren, so dass einige von ihnen erfassen können, andere nicht, sodass einige von ihnen wiederverwendet werden können, andere nicht.

Das ist alles für die aktuelle Implementierung. Eine zukünftige Implementierung könnte verschiedene, aber identische Lambda-Ausdrücke zu einer einzigen Instanz falten oder erkennen, wenn ein Lambda-Ausdruck nur Verweise auf wiederverwendbare Lambda-Instanzen erfasst, um sie ebenfalls wieder verwendbar zu machen. Dies könnte einen Kaskadeneffekt haben und die Anzahl der Instanzen dramatisch reduzieren.

Sie sagten, dass Sie bereits wissen, dass die Anzahl der Objekte nicht so wichtig ist. Aber es ist erwähnenswert, dass eine übermäßige Verwendung von andThen einen tiefen unausgewogenen Baum von Verbrauchern erzeugt, deren Ausführung der accept Methode eine beträchtliche Stapeltiefe erfordern kann.