爱马士的团长|Stream流式编程常见的坑,算我求你了!请避开Java( 二 )


这个时候你可以想到要将数组转成stream,于是有了第二个版本
Stream>arrStream=words.stream().map(word->word.split("-")).map(Arrays::stream);//output:java.util.stream.ReferencePipeline$Head@2c13da15,//java.util.stream.ReferencePipeline$Head@77556fdarrStream.forEach(System.out::println);复制代码还是不对 , 这个问题使用flatMap扁平流可以解决 , flatMap将流中每个元素取出来转成另外一个输出流
StreamstrStream=words.stream().map(word->word.split("-")).flatMap(Arrays::stream).distinct();//output:hellojava8streamstrStream.forEach(System.out::println);复制代码filter操作
filter接收Predicate对象 , 按条件过滤 , 符合条件的元素生成另外一个流 。
//过滤出单词长度大于5的单词 , 并打印出来Listwords=ImmutableList.of("hello","java8","hello","stream");words.stream().filter(word->word.length()>5).collect(Collectors.toList()).forEach(System.out::println);//output:stream复制代码(2)终端操作
终端操作将stream流转成具体的返回值 , 比如List , Integer等 。 常见的终端操作有:foreach,min,max,count等 。
foreach很常见了 , 下面举一个max的例子 。
//找出最大的值Listintegers=Arrays.asList(6,20,19);integers.stream().max(Integer::compareTo).ifPresent(System.out::println);//output:20复制代码假如有一个需求:过滤出年龄大于20岁并且分数大于95的学生 。
使用for循环写法:
privateListgetStudents(){Students1=newStudent("xiaoli",18,95);Students2=newStudent("xiaoming",21,100);Students3=newStudent("xiaohua",19,98);ListstudentList=Lists.newArrayList();studentList.add(s1);studentList.add(s2);studentList.add(s3);returnstudentList;}publicvoidrefactorBefore(){ListstudentList=getStudents();//使用临时listListresultList=Lists.newArrayList();for(Students:studentList){if(s.getAge()>20&&s.getScore()>95){resultList.add(s);}}//output:Student{name=xiaoming,age=21,score=100}resultList.forEach(System.out::println);}复制代码使用for循环会初始化一个临时list用来存放最终的结果 , 整体看起来不够优雅和简洁 。
使用lambda和stream重构后:
publicvoidrefactorAfter(){ListstudentLists=getStudents();//output:Student{name=xiaoming,age=21,score=100}studentLists.stream().filter(this::filterStudents).forEach(System.out::println);}privatebooleanfilterStudents(Studentstudent){//过滤出年龄大于20岁并且分数大于95的学生returnstudent.getAge()>20&&student.getScore()>95;}复制代码使用filter和方法引用使代码清晰明了 , 也不用声明一个临时list , 非常方便 。
(1)误区一:重复消费stream对象
stream对象一旦被消费 , 不能再次重复消费 。
Liststrings=Arrays.asList("hello","java8","stream");Streamstream=strings.stream();stream.forEach(System.out::println);//okstream.forEach(System.out::println);//IllegalStateException复制代码上述代码执行后报错:
java.lang.IllegalStateException:streamhasalreadybeenoperateduponorclosed
(2)误区二:修改数据源
在流操作的过程中尝试添加新的string对象 , 结果报错:
Liststrings=Arrays.asList("hello","java8","stream");//expect:HELLOJAVA8STREAMWORLD,butthrowUnsupportedOperationExceptionstrings.stream().map(s->{strings.add("world");returns.toUpperCase();}).forEach(System.out::println);复制代码注意:一定不要在操作流的过程中修改数据源 。


推荐阅读