我一直在查看java FunctionalInterface java.util.function.Consumer,它有源代码
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);
}
}
我得到了Out Put
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 :(得分:0)
有意未指定在将lambda表达式计算为功能接口的实例时是否将创建新对象,另请参阅Does a lambda expression create an object on the heap every time it's executed?。
因此,我们不能对为此操作创建的对象实例的数量做出一般性声明,特别是对于可能存在可重用实例的相同代码的重复执行(这可能是重要的情况)。此外,Consumer.andThen
的确切实现并不固定,也不必像发布的代码。 default
方法可以覆盖也很重要,因此如果您调用Consumer
的第一个andThen
不是lambda表达式的结果,而是自定义实现的结果,它可能会更改整个结果显着。
实际上,使用当前实现,lambda表达式(T t) -> { accept(t); after.accept(t); }
将捕获对其他Consumer
个实例的两个引用,因此每个实例都会计算一个新的Consumer
个实例时间,就像你的具体类变体一样。因此,此andThen
次调用链将创建Consumer
个实例的不平衡树,就像您的变体一样。
但是,这并不意味着所有叶子消费者实例都是新实例。在您的示例中,所有叶函数都具有acceptC++; System.out.println("accept call "+ acceptC);
形式,这意味着捕获this
以便能够修改acceptC
,因此每次等效的lambda表达式将评估为新实例。但这不是真实的生活场景。在实践中,您将使用andThen
来组合不同的消费者,因此其中一些可能正在捕获,而另一些可能不会捕获,因此其中一些可能会被重用,而另一些则不会。
这就是当前实施的全部内容。未来的实现可能会将不同但相同的lambda表达式折叠到单个实例,或者识别lambda表达式何时捕获对可重用lambda实例的引用以使其可重用。这可能会产生级联效应,从而大大减少了实例数。
你说你已经意识到物体的数量并不重要。但值得注意的是,过度使用andThen
会产生一个深度不平衡的消费者树,其accept
方法的执行可能需要大量的堆栈深度。