Java8新特性 之流式编程Stream

文章目录

  • Stream特点
  • Stream语法
  • Stream创建
  • Stream对象方法使用
    • 中间操作
      • filter(过滤)
      • distinct(去重)
      • Sort(排序)
      • map(映射)重点
      • flatMap(映射)重点
    • 结束操作
      • forEach(遍历)
      • reduce(归约)
      • collect(搜集)

Stream特点

  • 代码简洁: 函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环。
  • 多核友好:Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下parallel()方法。
  • 无存储:stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。
  • 为函数式编程而生:对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。
  • 惰式执行:stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
  • 可消费性:stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。

使用Stream需要三个操作步骤:创建Stream、中间操作以及结束操作

注意:因为stream操作是延迟的,这就意味着它们会等到需要结果的时候才执行,只有有终止操作,流的相关操作才会执行。

Stream语法

Java8新特性 之流式编程Stream_第1张图片

Stream创建

stream并不是某种数据结构,它只是数据源的一种视图。这里的数据源可以是一个数组,Java容器或I/O channel等。正因如此要得到一个stream通常不会手动创建,而是调用对应的工具方法。

1、 调用Collection系列集合的串行流:stream()方法或者并行流: parallelStream()方法

List<String> list = Arrays.asList("tom", "James");
// 获取并行的Stream对象
Stream<String> stream = list.parallelStream();
// 获取串行的Stream对象
Stream<String> stream = list.stream();

2、调用Arrays.stream(T[] array)方法获取数组流

String[] array = {"aa", "bb", "cc"};
Stream<String> stream = Arrays.stream(array);

3、调用Stream.of()方法

Stream<String> stream = Stream.of("tom", "james");

4、其他方式
Stream.iterate()
Stream.generate()

Stream对象方法使用

Stream对象提供的方法分成两类:

  • 中间操作:将原始的Stream转换成另外一个Stream,并且总是会惰式执行,如filter返回的是过滤后的Stream。
  • 终端操作:产生的是一个结果或者其它的复合操作,如count或者forEach操作。

中间操作

方法 说明
sequential 返回一个相等的串行的Stream对象,如果原Stream对象已经是串行就可能会返回原对象
parallel 返回一个相等的并行的Stream对象,如果原Stream对象已经是并行的就会返回原对象
unordered 返回一个不关心顺序的Stream对象,如果原对象已经是这类型的对象就会返回原对象
onClose 返回一个相等的Steam对象,同时新的Stream对象在执行Close方法时会调用传入的Runnable对象
close 关闭Stream对象
filter 元素过滤:对Stream对象按指定的Predicate进行过滤,返回的Stream对象中仅包含未被过滤的元素
map 元素一对一转换:使用传入的Function对象对Stream中的所有元素进行处理,返回的Stream对象中的元素为原元素处理后的结果
mapToInt 元素一对一转换:将原Stream中的使用传入的IntFunction加工后返回一个IntStream对象
flatMap 元素一对多转换:对原Stream中的所有元素进行操作,每个元素会有一个或者多个结果,然后将返回的所有元素组合成一个统一的Stream并返回;
distinct 去重:返回一个去重后的Stream对象
sorted 排序:返回排序后的Stream对象
peek 使用传入的Consumer对象对所有元素进行消费后,返回一个新的包含所有原来元素的Stream对象
limit 获取有限个元素组成新的Stream对象返回
skip 抛弃前指定个元素后使用剩下的元素组成新的Stream返回
takeWhile 如果Stream是有序的(Ordered),那么返回最长命中序列(符合传入的Predicate的最长命中序列)组成的Stream;如果是无序的,那么返回的是所有符合传入的Predicate的元素序列组成的Stream。
dropWhile 与takeWhile相反,如果是有序的,返回除最长命中序列外的所有元素组成的Stream;如果是无序的,返回所有未命中的元素组成的Stream。

Java8新特性 之流式编程Stream_第2张图片
区分中间操作和结束操作最简单的方法,就是看方法的返回值,返回值为stream的大都是中间操作,否则是结束操作。

filter(过滤)

Java8新特性 之流式编程Stream_第3张图片

用于对Stream中的元素进行过滤,作用是返回一个只包含满足predicate条件元素的Stream。
函数原型:

Stream<T> filter(Predicate<? super T> predicate);

使用示例:

Stream<String> stream = Stream.of("I", "love", "you", "too");
// 保留长度等于3的字符串
stream = stream.filter(str -> str.length()==3);

由于filter()是个中间操作,如果只调用filter()不会有实际计算,因此也不会输出任何信息。

distinct(去重)

Java8新特性 之流式编程Stream_第4张图片

作用是返回一个去除重复元素之后的Stream。
函数原型:

Stream<T> distinct();

使用示例:

Stream<String> stream = Stream.of("I", "you", "too", "too");
// 去掉一个too字符串
stream = stream.distinct();

Sort(排序)

返回的是排序好后的Stream。
如果不指定一个自定义的Comparator则会使用默认排序。

@Test
public void test() {
    List<String> list = Arrays.asList("June", "Kmde", "Kang", "Zhan", "Gui");
    Stream<String> stream = list.stream();
    stream.sorted().forEach(System.out::println);
}

运行结果:
在这里插入图片描述

map(映射)重点

Java8新特性 之流式编程Stream_第5张图片

元素一对一转换。
它接收一个Funcation参数,用其对Stream中的所有元素进行处理,返回的Stream对象中的元素为Function对原元素处理后的结果 。
直观的说,就是对每个元素按照某种操作进行转换,转换前后Stream中元素的个数不会改变。
函数原型:

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

使用示例:

Stream<String> stream = Stream.of("I", "love", "you", "too");
// 将所有字符串转化成大写
stream = stream.map(str -> str.toUpperCase());
stream.forEach(System.out::println);

结果:

I
LOVE
YOU
TOO

从结果看出,流中的每个元素都应用了map()里的参数中的Function函数,并返回经过Function处理的元素。

flatMap(映射)重点

Java8新特性 之流式编程Stream_第6张图片

元素一对多转换。
它对原Stream中的所有元素使用传入的Function进行处理,每个元素经过处理后生成一个多个元素的Stream对象,然后将返回的所有Stream对象中的所有元素组合成一个统一的Stream并返回。转换前后元素的个数和类型都可能会改变。

函数原型:

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

使用示例:

Stream<List<Integer>> stream = Stream.of(Arrays.asList(1,2), Arrays.asList(3, 4, 5));
// 原来的stream中有两个元素,分别是两个List,执行flatMap()之后,将每个List都“摊平”成了一个个的数字,所以会新产生一个由5个数字组成的Stream
stream = stream.flatMap(list -> list.stream());

Stream<String> stream = Stream.of("tom", "James");
// 将每一个String元素拆分成单个字母的Stream
stream = stream.flatMap(n -> Stream.of(n.split("")));

map、flatMap区别:

  • map一对一转化,将一个流中的所有元素按照逻辑执行后并返回。
  • flatMap一对一或者一对多,将一个流中的所有元素都转换成另一个流,然后把所有的流连接起来成为一个流。

结束操作

方法 说明
iterator 返回Stream中所有对象的迭代器;
spliterator 返回对所有对象进行的spliterator对象
forEach 对所有元素进行迭代处理,无返回值
forEachOrdered 按Stream的Encounter所决定的序列进行迭代处理,无返回值
toArray 返回所有元素的数组
reduce 使用一个初始化的值,与Stream中的元素一一做传入的二合运算后返回最终的值。每与一个元素做运算后的结果,再与下一个元素做运算。它不保证会按序列执行整个过程。
collect 根据传入参数做相关汇聚计算
min 返回所有元素中最小值的Optional对象;如果Stream中无任何元素,那么返回的Optional对象为Empty
max 与Min相反
count 所有元素个数
anyMatch 只要其中有一个元素满足传入的Predicate时返回True,否则返回False
allMatch 所有元素均满足传入的Predicate时返回True,否则False
noneMatch 所有元素均不满足传入的Predicate时返回True,否则False
findFirst 返回第一个元素的Optioanl对象;如果无元素返回的是空的Optional; 如果Stream是无序的,那么任何元素都可能被返回。
findAny 返回任意一个元素的Optional对象,如果无元素返回的是空的Optioanl。
isParallel 判断是否当前Stream对象是并行的

forEach(遍历)

作用是对容器中的每个元素执行action指定的动作,也就是对元素进行遍历。
函数原型:

void forEach(Consumer<? super E> action)

使用示例:

// 使用Stream.forEach()迭代
Stream<String> stream = Stream.of("I", "love", "you", "too");
stream.forEach(System.out::println);

运行结果:
在这里插入图片描述
由于forEach()是结束方法,上述代码会立即执行,输出所有字符串。

reduce(归约)

规约操作(reduction operation)又被称作折叠操作(fold),是通过某个连接动作将所有元素汇总成一个汇总结果的过程。元素求和、求最大值或最小值、求出元素总个数、将所有元素转换成一个列表或集合,都属于规约操作。
Stream类库有两个通用的规约操作reduce()collect(),也有一些为简化书写而设计的专用规约操作,比如sum()、max()、min()、count()等。
最大或最小值这类规约操作很好理解(至少方法语义上是这样),我们着重介绍reduce()collect(),这是比较有魔法的地方。
使用示例:

 @Test
 public void test() {
     List<Integer> list = Arrays.asList(1, 2, 3, 4);
     // x:上一次执行的返回值,默认0;y:当前遍历的值
     Integer sum = list.stream().reduce(0, (x, y) -> {
         System.out.println("上次的返回值:" + x);
         System.out.println("这一次遍历的值:" + y);
         return x + y;
     });
     System.out.println("总和:" + sum);
     System.out.println("---黄金分割线---");

     List<String> list2 = Arrays.asList("June", "Kmde", "Kang", "Zhan", "Gui");
     Optional<String> result = list2.stream().reduce((x, y) -> x + "_" + y);
     System.out.println(result.get());
 }

运行结果:
Java8新特性 之流式编程Stream_第7张图片

collect(搜集)

接收的参数是将流中的元素累积到汇总结果的各种方式(称为收集器)。

可以转化成List、Set、Map …

// 把流中所有元素收集到List中
List<String> names = stream1.map(Student::getName).collect(Collectors.toList());
// 把流中所有元素收集到Set中,删除重复项
Set<String> names = stream1.map(Student::getName).collect(Collectors.toSet());
// 把流中所有元素收集到给定的供应源创建的集合中
Set<String> names = stream1.map(Student::getName).collect(Collectors.toCollection(HashSet::new));
// 把流中所有元素收集到Map中
Map<Integer, String> names = stream1.distinct().collect(Collectors.toMap(Student::getId, Student::getName));

//将集合中所有的名字连接在一起,并逗号分割
String allNameStr1 = stuList.stream().map(Stu::getName).collect(Collectors.joining(","));

参考:
https://segmentfault.com/a/1190000019143092
Java8新特性学习-Stream的Reduce及Collect方法详解

你可能感兴趣的:(#,Java8新特性)