关于Java的惰性求值

2023-05-22,,

最近在学scala的时候,函数传参可以是传名参数,或者传值参数

1.Scala中的传名参数是什么意思?lazy关键字有什么作用?

Scala官方文档的定义是:传名参数 仅在被使用时触发实际参数的求值运算。 它们与 传值参数 正好相反。 要将一个参数变为传名参数,只需在它的类型前加上 =>。

def calculate(input: => Int) = input * 37

测试输出

  def main(args: Array[String]): Unit = {

    def input(): Int ={
println("Initialized")
1
}
lazy val i = input();
println("begin for loop")
for( a <- 1 to 3){ val cal = calculate(i)
println("cal:" + cal)
} }

output:

begin for loop
Initialized
cal:37
cal:37
cal:37

可以看到Initialized是在begin for loop后面打印出来,而且可以看到Initialized在三次循环调用中,只输出了一次,这是因为有缓存的,只会在第一次使用的时候进行初始化。

2.在Java中如何实现类似的功能?

其实单纯的惰性求值,是很好实现的,可以通过Java 8 中的 functional interface Supply来传递参数。

    public static Integer calculate(Supplier<Integer> s) {
return s.get() * 37;
} public static void main(String[] args) { Supplier<Integer> input = () -> {
System.out.println("Initialized");
return 1;
}; System.out.println("begin for loop");
for (int i = 0; i < 3; i++) {
Integer cal = calculate(input);
System.out.println("cal:" + cal);
} }

output:

begin for loop
Initialized
cal:37
Initialized
cal:37
Initialized
cal:37

可以看到虽然实现了惰性求值,但是每次调用的时候supplier都会去计算一遍,这个时候可以用guava提供的MemoizingSupplier

    public static Integer calculate(Supplier<Integer> s) {
return s.get() * 37;
} public static void main(String[] args) { //这里返回的其实是MemoizingSupplier
com.google.common.base.Supplier<Integer> input = Suppliers.memoize(() -> {
System.out.println("Initialized");
return 1;
}); System.out.println("begin for loop");
for (int i = 0; i < 3; i++) {
Integer cal = calculate(input);
System.out.println("cal:" + cal);
}
}

output:

begin for loop
Initialized
cal:37
cal:37
cal:37

通过输出可以看到,实现的效果和scala是一样的,做到了惰性求值,且有缓存,只会被执行一次。

关于Java的惰性求值的相关教程结束。

《关于Java的惰性求值.doc》

下载本文的Word格式文档,以方便收藏与打印。