关于Java的惰性求值

最近在学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是一样的,做到了惰性求值,且有缓存,只会被执行一次。

原文地址:https://www.cnblogs.com/IC1101/p/15153989.html