Lambda表达式、Stream流
Lambda表达式
lambda表达式本质上是在本类的一个方法里面执行的;所以lambda表达式里面的this会指向当前类;
若lambda表达式里面用了this,则生成的方法是非静态的;否则是静态的;
静态方法和实例方法的区别在于实例方法有this;
java里面默认把this作为参数,放到实例方法的第一个参数;
惰性求值
String msg = "打印一些日志:" + this
logger.fine(msg);
// 即使最后不打印日志,但字符串的拼接工作还是会执行
logger.fine(() -> "打印一些日志:" + this);
// 使用了lambda表达式之后,字符串的拼接放到一个函数里面,fine日志需要打印的时候才去调用这个方法才真正执行!
stream流编程
stream流中也使用惰性求值(外部迭代关注怎么做、内部迭代关注做什么);
import java.util.stream.IntStream;
public class StreamDemo1 {
public static void main(String[] args) {
int[] nums = { 1, 2, 3 };
// 外部迭代
int sum = 0;
for (int i : nums) {
sum += i;
}
System.out.println("结果为:" + sum);
// 使用stream的内部迭代
// map就是中间操作(返回stream的操作)
// sum就是终止操作
int sum2 = IntStream.of(nums).map(StreamDemo1::doubleNum).sum();
System.out.println("结果为:" + sum2);
System.out.println("惰性求值就是终止没有调用的情况下,中间操作不会执行");
IntStream.of(nums).map(StreamDemo1::doubleNum);
}
public static int doubleNum(int i) {
System.out.println("执行了乘以2");
return i * 2;
}
}
操作类型分类
首先分为中间操作和最终操作;在最终操作没有调用的情况下,所有的中级操作都不会执行;
一般来说:返回stream流的就是中间操作,可以继续链式调用下去;不是返回stream流的就是最终操作;
最终操作里面又分为短路操作和非短路操作;短路操作例如limit/findxxx/xxxMatch这种,就是为了找到符合条件的就终止,其他的就是非短路操作;
中间操作也分为有状态操作和无状态操作;状态就是和其他数据有关系;
如果方法只有一个参数,那就是无状态操作,否则就是有状态操作;
在多个操作的时候,我们需要把无状态操作写在一起,有状态操作放到最后,这样效率会更加高;
package com.jxsr.controller;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
public class TestController {
public static void main(String[] args) {
Random random = new Random();
// 随机产生数据
Stream<Integer> stream = Stream.generate(() -> random.nextInt())
// 产生500个 ( 无限流需要短路操作. )
.limit(5)
// 第1个无状态操作
.peek(s -> print("peek: " + s))
// 第2个无状态操作
.filter(s -> {
print("filter: " + s);
return s > 1000000;
})
// 有状态操作
.sorted((i1, i2) -> {
print("排序: " + i1 + ", " + i2);
return i1.compareTo(i2);
})
// 又一个无状态操作
.peek(s -> {
print("peek2: " + s);
})
// 多线程(并行)
.parallel();
// 终止操作
stream.count();
}
public static void print(String s) {
// System.out.println(s);
// 带线程名(测试并行情况)
System.out.println(Thread.currentThread().getName() + " > " + s);
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException e) {
}
}
}
大家自己测试一下代码,能发现stream的调用方法,就像现实中的流水线一样,一个元素只会迭代一次,但如果中间有无状态操作,前后的操作会单独处理(元素就会被多次迭代);
(个人理解,不一定对)经过无状态操作时每个元素单独过;经过有状态操作时所有元素一起过;
参考链接