Java 8 Streams的简单使用方法
1 package JDK8Test; 2 import java.util.ArrayList; 3 4 public class Main 5 { 6 public static void main(String[] args) 7 { 8 ArrayList<Integer> nums=new ArrayList<Integer>(); 9 nums.add(1); 10 nums.add(null); 11 nums.add(3); 12 nums.add(4); 13 nums.add(null); 14 nums.add(6); 15 int n=(int)nums.stream().filter(num->num!=null).count(); 16 System.out.println(n);//4 17 } 18 }
上面这段代码是获取一个List中,元素不为null的个数。
红色框中的语句是一个Stream的生命开始的地方,负责创建一个Stream实例;绿色框中的语句是赋予Stream灵魂的地方,把一个Stream转换成另外一个Stream,红框的语句生成的是一个包含所有nums变量的Stream,通过绿框的filter方法以后,重新生成了一个过滤掉原nums列表所有null以后的Stream;蓝色框中的语句是丰收的地方,把Stream的里面包含的内容按照某种算法来汇聚成一个值。
使用Stream的基本步骤:
1.创建Stream;
2.转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换);
3.对Stream进行聚合操作,获取想要的结果;
怎么得到Stream:
①使用Stream静态方法来创建Stream:
of方法:有两个重载方法,一个接受变长参数,一个接受单一值
Stream integerStream = Stream.of(1, 2, 3, 5);
Stream stringStream = Stream.of(“taobao”);
②通过Collection接口的默认方法stream(),把一个Collection对象转换成Stream。
转换Stream:
转换Stream其实就是把一个Stream通过某些行为转换成一个新的Stream。
①distinct: 对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals方法),新生成的Stream中没有重复的元素;
②filter: 对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素;
③map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。这三个方法也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。
例子:
1 package JDK8Test; 2 import java.util.*; 3 import java.util.Arrays; 4 import java.util.stream.Collectors; 5 6 public class Main 7 { 8 public static void main(String[] args) 9 { 10 List<String> list=Arrays.asList(new String[] {"Ni","Hao","Lambda"}); 11 List<String> list2=list.stream().map(item->item.toLowerCase()).collect(Collectors.toList()); 12 System.out.println(list2); 13 }//[ni, hao, lambda] 14 }
这段代码就是对一个字符串的列表,把其中包含的每个字符串都转换成全小写的字符串。注意代码第四行的map方法调用,这里map方法就是接受了一个lambda表达式。
1 package JDK8Test; 2 import java.util.*; 3 import java.util.Arrays; 4 import java.util.stream.Collectors; 5 6 public class Main 7 { 8 public static void main(String[] args) 9 { 10 List<String> list=Arrays.asList(new String[] {"Ni","Hao","Lambda"}); 11 List<String> list2=list.stream().map(item->{return "lambda:"+item;}).collect(Collectors.toList()); 12 list2.forEach(System.out::println); 13 } 14 } 15 /* 16 lambda:Ni 17 lambda:Hao 18 lambda:Lambda 19 */
集合的forEach()方法,对集合进行遍历,小括号中的方法就是应用到集合中每个元素的身上,以达到遍历的目的。
1 package JDK8Test; 2 import java.util.*; 3 import java.util.Arrays; 4 import java.util.stream.Collectors; 5 6 public class Main 7 { 8 public static void main(String[] args) 9 { 10 String waibu="lambda:"; 11 List<String> proStrs=Arrays.asList(new String[] {"Ni","Hao","Lambda"}); 12 List<String> exeStrs=proStrs.stream().map(chuandi->{ 13 long zidingyi=System.currentTimeMillis(); 14 return waibu+chuandi+"------:"+zidingyi; 15 }).collect(Collectors.toList()); 16 exeStrs.forEach(System.out::println); 17 } 18 } 19 /* 20 lambda:Ni------:1559118070052 21 lambda:Hao------:1559118070052 22 lambda:Lambda------:1559118070052 23 */
lambda表达式可以访问给它传递的变量,访问自己内部定义的变量,同时也能访问它外部的变量。 不过lambda表达式访问外部变量有一个非常重要的限制:变量不可变(只是引用不可变,而不是真正的不可变)。 当在表达式内部修改waibu = waibu + " ";时,IDE就会报错。因为变量waibu被lambda表达式引用,所以编译器会隐式的把其当成final来处理。
以前Java的匿名内部类在访问外部变量的时候,外部变量必须用final修饰。现在java8对这个限制做了优化,可以不用显示使用final修饰,但是编译器隐式当成final来处理。
④peek: 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数;
⑤limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;
⑥skip: 返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream;
汇聚Stream:
汇聚操作(也称为折叠)接受一个元素序列为输入,反复使用某个合并操作,把序列中的元素合并成一个汇总的结果。比如查找一个数字列表的总和或者最大值,或者把这些数字累积成一个List对象。Stream接口有一些通用的汇聚操作,比如reduce()和collect();也有一些特定用途的汇聚操作,比如sum(),max()和count()。注意:sum方法不是所有的Stream对象都有的,只有IntStream、LongStream和DoubleStream实例才有。
①reduce():把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),返回单个的结果值,并且reduce操作每处理一个元素总是创建一个新值。
②collect:正如其名字显示的,它可以把Stream中的所有元素收集到一个结果容器中(比如Collection)。
Java 8还给我们提供了Collector的工具类——Collectors,其中已经定义了一些静态工厂方法,比如Collectors.toCollection()收集到Collection中, Collectors.toList()收集到List中和Collectors.toSet()收集到Set中。
List numsWithoutNull = nums.stream().filter(num -> num != null).collect(Collectors.toList());
③count方法:获取Stream中元素的个数。
– 搜索相关
– allMatch:是不是Stream中的所有元素都满足给定的匹配条件
– anyMatch:Stream中是否存在任何一个元素满足匹配条件
– findFirst: 返回Stream中的第一个元素,如果Stream为空,返回空Optional
– noneMatch:是不是Stream中的所有元素都不满足给定的匹配条件
– max和min:使用给定的比较器(Operator),返回Stream中的最大|最小值
下面给出allMatch和max的例子:
1 package JDK8Test; 2 import java.util.*; 3 4 5 public class Main 6 { 7 public static void main(String[] args) 8 { 9 ArrayList<Integer> nums=new ArrayList<Integer>(); 10 nums.add(1); 11 nums.add(null); 12 nums.add(3); 13 nums.add(4); 14 nums.add(null); 15 nums.add(6); 16 System.out.println(nums.stream().filter(item->item!=null).allMatch(item->item<100)); 17 } 18 } 19 /* 20 true 21 */
以上代码,判断nums列表里的不为null元素是否都满足“小于100“这个条件,输出为true。
1 package JDK8Test; 2 import java.util.*; 3 4 5 public class Main 6 { 7 public static void main(String[] args) 8 { 9 ArrayList<Integer> nums=new ArrayList<Integer>(); 10 nums.add(1); 11 nums.add(null); 12 nums.add(3); 13 nums.add(4); 14 nums.add(null); 15 nums.add(6); 16 nums.stream().filter(item->item!=null).max((o1,o2)->o1-o2).ifPresent(System.out::println); 17 } 18 } 19 /* 20 6 21 */
以上代码,先把nums里为null的元素过滤掉,然后输出nums里元素的最大值。输出为6。