<>Java8新特性学习(三)- Stream类

<>背景及介绍


这里提到Java8的Stream类并不像Java以前版本的InputStream和OutputStream,他们是几乎不搭边的两个类。Stream类常跟集合处理一起使用,算是集合的一个增强。Stream类比前面提到的Optional类更加通用,原因在于Stream类提供更丰富的API,满足了程序中通用的集合处理方法,且使用lambda方便,较Java7减少较多的代码。

<>举例说明


使用Stream和lambda编码,可以提高代码效率,对于过滤取值这种常规操作,相比起java7来实现高效简单。下面举例说明,假设我们有一组求职者的简历集合,我们需要从中过滤具有3年以上工作经验,且有高并发技能的Java开发工程师的求职者,得到他们的手机号,进行面试邀约。
public class Resume { private String name; private Integer workingAge; private
List<String> skillList; private String job; private String phone; } //java7 List
<String> phoneList = new ArrayList<>(); for (Resume resume : resumeList) { if (
resume.getWorkingAge() < 3) { continue; } if (!resume.getSkillList().contains(
"高并发")) { continue; } if (!"Java".equals(resume.getJob())) { continue; }
phoneList.add(resume.getPhone()); } //java8 List<String> phoneList = resumeList.
stream() .filter(resume -> resume.getWorkingAge() >= 3) .filter(resume -> resume
.getSkillList().contains("高并发")) .filter(resume -> "Java".equals(resume.getJob()
)) .map(Resume::getPhone).collect(Collectors.toList());
<>重要方法介绍

<>java.util.Collection#stream#parallelStream

集合类对象可以直接通过stream()/paralleStream()方法创建串行流和并行流。如
List<String> phoneList = resumeList.stream() .map(Resume::getPhone).collect(
Collectors.toList());
<>of\generate


of()用来显式创建串行的Stream对象,有两个重载方法,一个是元素个数不限,另一个只能传一个值。基础数据类型的流,可以扩展使用IntStream、LongStream、DoubleStream.

特别说明:流只能使用一次,不然会抛异常java.lang.IllegalStateException: stream has already been
operated upon or closed.
//of() Stream<Integer> integerStream = Stream.of(1,2,3,4,5,6); integerStream.
filter(i -> i > 4).forEach(System.out::println);
这里创建的是串行的运行方式,如果想要创建并行的,可以通过Colletion#parallelStream()方法创建。of()方法暂时没有提供这个特性。


generate()方法可以自己生成控制Stream,这个方法适合用来创建常量的Stream或者随机元素的Stream。generate()是无限生成流的,需要配合limit()来使用.下面举例在1000个数字中随机抽取5个幸运中奖号码.
//generate() Stream.generate(() -> new Random().nextInt(1000)).limit(5).forEach
(System.out::println);
<>filter

filter会对Stream中的所有元素进行过滤,会创建一个新的Stream,其元素均符合过滤条件。如文章开头举例的简历过滤:
//java8 List<String> phoneList = resumeList.stream() .filter(resume -> resume.
getWorkingAge() >= 3) .filter(resume -> resume.getSkillList().contains("高并发")) .
filter(resume -> "Java".equals(resume.getJob())) .map(Resume::getPhone).collect(
Collectors.toList());
<>map/flatMap


map和flatMap都可以被用在一个Stream对象上,且都能返回Stream.不同之处在于map操作会对每一个输入返回一个结果,然而flatMap操作会返回任意个(0个/1个/多个)值.这取决于在每个方法上的操作。


map操作接受一个Function,会将传入的每个值都调用改Function,然后得到结果后返回。而flatMap操作会对每个参数产生任意数量结果。在Java编程中,返回任意结果可能会在处理时比较麻烦,需要考虑更多的情况,因为返回值可能是一个值,Array或List。我们可以把flatMap操作可以看成是map操作
+ flat操作,首先应用Function得到结果,然后将结果flat出来。而map操作相比flatMap操作则可以视为没有最后的flat操作。下面举例:
@Test public void testFlatMap() { List<Integer> intList1 = new ArrayList<>();
intList1.add(1); intList1.add(2); List<Integer> intList2 = new ArrayList<>();
intList1.add(3); intList1.add(4); List<Integer> list = Stream.of(intList1,
intList2).flatMap(List::stream).collect(Collectors.toList()); System.out.println
(list); //[1, 2, 3, 4] }
再举例,现在有几个单词,想过滤单词中不重复的字母。map操作无法得到,而flatMap可以得到。
//map List<Stream<String>> sMap = Arrays.stream(words).map(word ->
word.split("")) .map(Arrays::stream).distinct() .collect(Collectors.toList());
//flatMap List<String> sFlatMap = Arrays.stream(words).map(word ->
word.split("")) .flatMap(Arrays::stream).distinct()
.collect(Collectors.toList()); System.out.println(sFlatMap); //[J, A, V, G, O]
Stream map(Function<? super T, ? extends R> mapper);

Stream flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

<>collect

collect方法用于将Stream流中的对象转化还原为流的结果。如
List<String> asList = stringStream.collect(Collectors.toList()); Map<String,
List<Person>> peopleByCity = personStream.collect(Collectors.groupingBy(Person::
getCity)); Map<String, Map<String, List<Person>>> peopleByStateAndCity =
personStream.collect(Collectors.groupingBy(Person::getState, Collectors.
groupingBy(Person::getCity)));
<>anyMatch\allMatch

anyMatch:检测是否流中是否有任一元素满足提供Predicate.

allMatch:检测是否流中是否所有元素满足提供Predicate.
boolean anyMatch = Stream.of(1, 2, 3, 4, 5, 6).anyMatch(i -> i > 6); System.out
.println(anyMatch);//false boolean allMatch = Stream.of(1, 2, 3, 4, 5, 6).
allMatch(i -> i < 20); System.out.println(allMatch);//true
<>min\max

根据参数Comparator返回流中最大\小的元素,返回类型是Optional。更多Optional信息,请查看
Java8新特性学习(二)- Optional类
<https://blog.csdn.net/codingtu/article/details/87826793>
Optional<Integer> optionalMin = Stream.of(1, 2, 3, 4, 5, 6).min((a, b) -> a >
b? 1 : -1); System.out.println(optionalMin.orElse(null));//1 Optional<Integer>
optionalMax= Stream.of(1, 2, 3, 4, 5, 6).max(Integer::compareTo); System.out.
println(optionalMax.orElse(null));//6
<>skip\limit

skip:返回除去前n个元素之外剩余元素组成的流。如果全部被抛弃,则返回一个空流。

limit:返回最大元素个数不超过n的流
Stream.of(1,2,3,4,5,6).skip(20l).forEach(System.out::print); Stream.of(1,2,3,4
,5,6).limit(3l).forEach(System.out::print);
<>reduce

reduce是关联累积函数对流的元素进行缩减,并返回缩减之后的Optional类型的结果。

reduce()提供了3种方式使用
1、Optional<T> reduce(BinaryOperator<T> accumulator);//返回值是Optional 2、T reduce(
T identity, BinaryOperator<T> accumulator);//返回值是T,identity一样的类型 3、<U> U reduce(
U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
; //返回值是U,identity一样的类型,accumulator累加器,combiner:结合器
举例使用
System.out.println(Stream.of(1,2,3,4,5,6).reduce( (a, b) -> a+b).orElse(0));
System.out.println(Stream.of(1,2,3,4,5,6).reduce(0, (a, b) -> a+b));

这里会对Stream中的元素遍历每一个,进行BinaryOperator的apply操作,并最终返回一个类似合并各元素之后的结果。而我们常用的sum,max,min等操作都是一种特殊的reduce操作。可以看IntStream中min()函数的实现:
public final OptionalInt min() { return reduce(Math::min); }
<>总结

* Stream不是一种数据结构
* Stream并不会自己存储数据,而是利用原数据进行操作
* Stream只能使用一次,使用多次会抛出异常
* 具有串行和并行能力,简单高效就能写出高并发代码

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信