a这并不是要对令人畏惧的函数式编程进行谴责,而是对编程中很容易发生的一些错误进行警醒。 高阶函数是函数式编程的关键,因此,谈论它们会帮助你在派对上成为关注的焦点。 alert('10 Seconds passed'); },10000); 上面的settimeout 函数就是一个高阶函数。它的参数是一个匿名函数。10秒后,它将会用这个匿名函数作为参数来调用。 我们可以编写另一个简单的高阶函数,作为结果提供给上面的函数: } }; 在函数式编程中,上面是很常见的做法。由高阶函数返回的函数被调用时,将会捕捉外部作用域,并且能够在这个作用域上进行操作。 出于同样的原因。高阶函数(方法)返回的函数(lambda函数)被调用的时候,会捕捉外部作用域,并且能够在这个作用域上进行操作。 这里给出一个最简单的例子: classTest { Runnablerunnable = runnable; runnable.run;// Breakpoint here } staticRunnable runnable { return-> { System.out.println("Hello"); }; } } 在上面的逻辑中,如果在runnable.run 方法调用处做一个断点,可以看到在堆栈上无害的lambda实例。生成的一个简单类,提供了函数式接口的实现:
现在,把这个例子转换成普通的企业应用程序(注意注解)。为了方便博客的书写,我们做了很大的简化: classTest { publicstatic void main(String args) { Runnablerunnable = new EnterpriseBean .runnable; runnable.run;// Breakpoint here } } @ImportantDeclaration @NoMoreXML({ @CoolNewValidationStuff("Annotations"), @CoolNewValidationStuff("Rock") }) classEnterpriseBean { newObject[100_000_000]; Runnablerunnable { return-> { System.out.println("Hello"); }; } } 断点仍放在原来的地方。那么我们在堆栈中又能看到什么呢? 仍然是一个无害的lambda实例:
好吧,为了调试,我们现在添加一些日志: classTest { publicstatic void main(String args) { Runnablerunnable = new EnterpriseBean .runnable; runnable.run;// Breakpoint here } } @ImportantDeclaration @NoMoreXML({ @CoolNewValidationStuff("Annotations"), @CoolNewValidationStuff("Rock") }) classEnterpriseBean { ObjectenterpriseStateObject = newObject[100_000_000]; Runnablerunnable { return-> { //Some hARMless debugging here System.out.println("Hellofrom: " + this); }; } } 哦哦! 意外地,一个毫无影响的this 引用强迫Java编译器封装返回的Runnable类中EnterpriseBean 的外部类实例:
而且,同时返回的还有enterpriseStateObject 。这个对象现在不会被垃圾回收,直到调用点释放Runnable后才会释放。 好吧,现在这并不是什么新鲜事,不是吗? 确实,这并不是什么新鲜事。Java8 没有一流的函数,没关系。通过虚拟的SAM 类型支持匿名表达式的想法就相当的巧妙,因为在Java系统中它允许对所有现有的库更新和lambda-y-fy而并不改变它们。 而且,用一个匿名类,这整件事情就不会那么令人惊讶了。由于良好的Swing1.0风格ActionListener等,下面的编码风格通过内部类已经暴露了内部的状态。 classTest { public static voidmain(String args) { Runnablerunnable = new EnterpriseBean .runnable; runnable.run; } } @ImportantDeclaration @NoMoreXML({ @CoolNewValidationStuff("Annotations"), @CoolNewValidationStuff("Rock") }) classEnterpriseBean { ObjectenterpriseStateObject = Runnablerunnable { @Override System.out.println("Hello from" + EnterpriseBean.this); } }; } } 这里有什么心东西?匿名风格会鼓励在Java 中所有地方使用高阶函数。一般情况下是挺好的。但是,仅仅当高阶函数是一个静态方法时,其产生的类型不会封装任何状态。 然而,通过上面的例子,我们可以看到,在不久的将来,当我们开始拥抱Java 8 函数式编程风格时,我们在调试过程中将会时不时碰到一些内存泄露等问题。 所以,请谨慎使用并遵循以下规则: 延伸阅读 以前封闭实例(enclosinginstance)会出现一些问题。可以解了一下可怕的双花括号反模式在前20年是怎么给Java开发者带来痛苦和磨难的。 更多内容欢迎交流:qq:3306607541(高老师)
|