最近在我的课程里面SpringBoot2.0不容错过的新特性 WebFlux响应式编程里面,有学员提出了以下问题,在jdk10里面代码没有执行(课程中stream流是用jdk8演示的)
代码:
public class LambdaDemo { public static void main(String[] args) { IntStream.range(1,10).peek(LambdaDemo::debug).count(); } public static void debug(int i) { System.out.println(Thread.currentThread().getName() + " " + " debug " + i); try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }
jdk10运行不会产生结果,8就没有问题
我第一个感觉是不可能,觉得是学员搞错了,理论上jdk不可能不兼容的,让学员检查代码和环境。学员检查之后说确实如此,于是我在jdk10下运行测试,确实如学员所说,peek的日志没有打印出来。
看来即使工作校验再丰富的人,也会因为想当然犯错误。于是我翻了以下jdk10的api说明,最终发现不是代码没有执行,而是jdk10下调用count方法的时候,peek方法没有执行!
jdk说明:
api上说了,count方法的时候,peek不会执行。所以上面代码不是没有执行,而是peek方法没有执行
public class LambdaDemo { public static void main(String[] args) { long count = IntStream.range(1,10).peek(LambdaDemo::debug).count(); System.out.println("count=" + count); } public static void debug(int i) { System.out.println(Thread.currentThread().getName() + " " + " debug " + i); try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }
上面代码里面,可以打印出count=9,但peek日志没有打印(jdk8里面能打印)。需要说明的是,peek方法不是都不会执行,调用count不会执行,调用sum的时候就会执行!
我们学习一个新技术,学会api的使用只是其次的,最重要的是学会这种技术的思想。好比你学习了vue,但还是用jquery的思维来写代码,这都是不对的!回到我们的函数式编程里面,函数式编程里面,对象在流操作(函数操作里面)里面,不应该产生任何修改(副作用side-effects),修改对象的时候应该返回新对象。
如下代码,peek中修改了对象,产生了副作用(peek只应该用于debug作用,不应该有修改操作产生副作用)
import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.Collections; import java.util.List; class Demo{ public String msg = "初始值"; } public class LambdaDemo2 { public static void main(String[] args) { System.out.println("jdk版本:"+ManagementFactory.getRuntimeMXBean().getVmVersion()); List<Demo> demos = new ArrayList<Demo>(); demos.add(new Demo()); demos.add(new Demo()); // 这里peek中修改了对象,产生了副作用(side-effects) long count = demos.stream().peek(demo -> demo.msg = "peek中修改了").count(); System.out.println(count); // jdk8下下面的demo已经改变 // jdk10下没有 demos.stream().forEach(demo -> System.out.println(demo.msg)); } }
jdk8中,peek方法执行了,demo对象被修改了。输出
而jdk10中,peek没有执行,demo对象没有修改!
所以,函数式编程里面,函数应该是没有副作用的,对象不应该被修改产生副作用(如果要修改应该用map方法),大家一定要用函数式的思想来写函数式的代码!