内容来自《 java8实战 》,本篇文章内容均为非盈利,旨为方便自己查询、总结备份、开源分享。如有侵权请告知,马上删除。
书籍购买地址:java8实战
-
筛选和切片
//取出是素菜的菜单
menu.stream()
.filter(Dish::isVegetarian) //代表是否是素食,这里条件并不一定是方法调用,只要的你条件能够返回boolean就可以
.collect(Collectors.toList());
//取出菜单的前三个
menu.stream().limit(3) //跟sql中limit一样,不过这个是短路limit,也就是说,它取出了三个后就不再遍历后面的元素了,直接返回
.collect(Collectors.toList());
menu.stream()
.distinct() //去重操作,根据元素的hashCode和equals方法判断是否相等
.collect(Collectors.toList());
//取菜单中第三个到第五个
menu.stream()
.skip(2) //跳过开头两个元素
.limit(3) //然后截取第三个到第五个
.forEach(System.out::println);
//如上可以看出skip和limit是互补的,因为limit没有这样的形式:limit(start,end)
-
映射
- 提到这个概念,就是把你stream里的每个元素都应用到自己指定的表达式之上然后返回,就比如
List<String> list = Arrays.asList("1","2","3");
list.stream()
.映射方法(str -> str + "dada")
.forEach(System.out::println);
//以上为伪代码
//说明的意思就是list中的每个元素:1,2,3都会应用到表达式:str + "dada"
//并返回表达式的值
//所以结果就是1dada,2dada,3dada
//这里提到的map方法,完全可以替换上面的伪代码:映射方法,上面代码是传入A类型返回A类型的演示
//也就是传入字符串1,2,3返回的也是字符串
//map当然可以传入A类型返回B类型,比如
List<String> list = Arrays.asList("1","2","3");
list.stream()
.map(Integer::parseInt)
.forEach(System.out::println);
//上面就是传入String,返回的是int
//当然也可以是返回字符串的长度
查找和匹配
List<String> list = Arrays.asList("1","2","3","4");
boolean b = list.stream().anyMatch(s -> s.equals("1")); //true
List<String> list = Arrays.asList("1","2","3","4");
boolean b = list.stream().allMatch(s -> Integer.parseInt(s) < 5); //true
List<String> list = Arrays.asList("1","2","3","4");
boolean b = list.stream().noneMatch(s -> Integer.parseInt(s) > 5); //true
- 如上的方法都具有短路效果,意思就是主要遇到一个不匹配条件的元素就立刻返回true或者false
- findAny:找任意一个
List<String> list = Arrays.asList("1","2","3","4");
Optional<String> any = list.stream().findAny();
System.out.println(any.get()); //虽然书上说是任意一个,但是我一直返回的是1
//自己测试的将元素添加到十个,stream依旧是1,但是使用并行流parallelStream,将随机返回,但是依然是区间比较小
- Option以后的帖子会说到的,你可以看一下我相关的帖子,只要记住Option是一个值的容器,因为findAny找的可能是个空列表,所以他可能会返回null,然后将返回的这个值包装在Option中,然后调用get方法就会出现返回的值,如果Option中没有值还get那么就会报错,现在只要知道这点就可以了
List<String> list = Arrays.asList("1","2","3","4");
Optional<String> any = list.stream().findFirst();
System.out.println(any.get()); //1
归约reduce
- 上面的映射和这词提到的归约可以一起使用,类似hadoop中的mr模型
- 元素求和
int[] is = {1,2,3,4,5,6,7,8,9};
Arrays.stream(is).reduce(0,Integer::sum);//45
//以0为起始值,所以如果数组内没有元素,也不至于null,然后依次相加
//0+1=1
//1+2=3
//3+3=6
//6+4=10 ....
int[] is = {1,2,3,4,5,6,7,8,9};
OptionalInt reduce = Arrays.stream(is).reduce(Integer::sum);
System.out.println("reduce = " + reduce.getAsInt());//45
//OptionalInt的出现就是因为它没有初始值进行累加,所以如果数组为空,那么将返回null
//OptionalInt使用方法和Optional一样,只是方法名变了一下,目前只知道这些就好了
//max
int[] is = {1,2,3,4,5,6,7,8,9};
OptionalInt reduce = Arrays.stream(is).reduce(Integer::max);
System.out.println("reduce = " + reduce.getAsInt()); //9
//求最小改为min方法即可,也可以自己实现
OptionalInt reduce = Arrays.stream(is).reduce((a,b) -> a > b ? a : b );
-
归约方法的优势和并行化
- 求和方法:定义一个int变量,然后迭代去加。相比之下reduce将其转换为了内部迭代。而且迭代要去求和并且更新我们的一个int共享变量,这对于并行化来说并不容易实现,如果加入了同步,可能线程切换的开销就已经抵消了并行带来的性能提升。(可变的变量累计器对于并行来说并不好),如上的代码为了实现并行只需要把stream方法改为parallelStream()即可
int[] is = {1,2,3,4,5,6,7,8,9};
int sum = 0; //int共享变量
//这只是单线程的,如果是多线程的话,为了保证sum的正确肯定要sync。
//所以这就是说的共享变量并不适合于并行化
for (int i : is) {
sum += i; //更新共享变量
}
-
流操作的有状态和无状态
- 如果你购买了书可以先去看看书的定义,下面是我自己的理解
int[] is = {1,2,3,4,5,6,7,8,9};
Arrays.stream(is)
.filter(i -> i > 3) //无状态
.map(i -> i + 1) //无状态
.distinct() //有状态
.max(); //有状态
- 对于上面来说,filter和map只是接收一个元素然后过滤映射一个元素,这个元素处理完就交给下面的方法处理了,自己并不保留这个元素,这样的叫做无状态
- 那distinct和max来说,他不能接收一个处理一个然后再交给下面的方法处理,因为它需要拿到整个元素来去重和去最大值,如果拿到部分他肯定是不能做这些操作的,元素就暂时的保留在了方法中,所以这样的叫做有状态
接下来的东西下一篇讲