[Java详解]Java8新特性--stream

[Java详解]Java8新特性–stream

在食用此文章之前请先移步Lamda表达式

什么是StreamAPI

Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程 序员的生产力,让程序员写出高效率、干净、简洁的代码。

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用 Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。 也可以使用 Stream API来并行执行操作。简言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

以上都是废话 实际上StreamAPI给了开发者一个更好的操作数据的方法。让对数据的操作变得更加的方便。给了我们一个新的优雅美丽的方法。

Stream如何创建

简单分成基于数组与基于流吧

  • 基于数组

在Java8之后,关于Arrays与Collection的接口被拓展啦。所以可以直接在对象上面调用方法

ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);
integers.add(4);Stream<Integer> listStream = integers.stream();

也可以使用Arrays方法

Integer[]  arr = {123,321,12321,123,33,22,11,2132};
Stream<Integer> stream = Arrays.stream(arr);
  • 基于流

调用Stream.of(T... values)

这种方法使用条件是,数据存在且固定:

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);

调用Stream.concat(Stream1, Stream2)

使用条件是有两个流,将两个流中的数据合并成一个

Stream.concat(stream1, stream2);

使用无限流

这种使用条件是,数据需要运算,且数据量未知:

有两种方法

  1. 迭代Stream.iterate(0, t -> t + 2)

  2. 生成Stream.generate(Math::random)

比如

// 遍历前100个等差数列
Stream.iterate(1, t -> t * 2).limit(100).forEach(System.out::println);
// 生成无限个整形(会出大问题,只是为了演示,故意写错的)
Stream.generate(new Random()::nextInt).forEach(System.out::println);

注意: 无限流,顾名思义,无穷无尽。在使用这种方法的时候,必须加上.limit(int lenght)来限制范围。

关于迭代生成

表面看上去有点抽象,因此抽出来说了。

对于参数(seed, f),官方注释是这么描述的

seed – the initial element 
f – a function to be applied to the previous element to produce a new element

也就是说seed 是初始参数。相当于for(int i = 0; i ++ ; i < 10)中的int i = 0f 是对于seed 的操作。相当于i++ 最后的limit(10)相当于数据大小。也就是i < 10.

StreamAPI能干什么

正如开头所说,StreamAPI实际上是对数据的一种操作。因此讨论到StreamAPI能干什么的时候,不如去想一下,关于数据需要什么操作

基于遍历

在实际开发中,遍历一组数据的情况确确实实的存在。但是遍历有一个前提:对每一个数据进行同样的操作。

根据操作的方法与操作的结果,分成两类:映射、筛选

映射

可以这样去写出来一个代码:

Integer[]  arr = {123,321,12321,123,33,22,11,2132};
for (int num : arr) {
    num += 1024;
    System.out.println(num); // 输出数组中的每一个元素+1024后的值
}

虽然看上去有点意义不明。但是实际上这是一个非常经典的例子:对数组进行遍历,对元素进行操作。

虽然进行了操作。但是实际上arr数组本身没有变化。也就是这样的操作没有被保存下来,无法进行下一步操作。换句话说:如果要对操作后的数据进行操作,需要更加复杂的代码。

在这种前提下,看一下StreamAPI是怎么做的:

Stream<Integer> stream = Arrays.stream(arr);
stream.map(num -> num + 1024).forEach(System.out::println);

是的,利用Stream和Lamda表达式。用了非常优雅的方式完成了这个操作。

除此之外,仔细观察就能发现Stream.map()的返回值依然是Stream。这意味着想要对结果进行后续操作也十分简单,后面会说。

诸如此类还有一下几种。功能一样,返回值不同

方法描述
  1. map(Function f)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  2. mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
  3. mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
    4.mapToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
  4. flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
筛选与切片

其实上文已经提到过相关的方法了。.limit()其实就是一种切片的方法。除了选出前10个,当然也会存在选出后10个的方法。

截断与跳过

方法描述skip(long n)跳过元素,返回一个扔掉了前 n个元素的流。若流中元素不足 n个,则返回一个空流。与 limit(n) 互补limit(long maxSize)截断流,使其元素不超过给定数量

Integer[]  arr = {123,321,12321,123,33,22,11,2132};
Stream<Integer> stream = Arrays.stream(arr);
stream.limit(3).forEach(System.out::println);Integer[]  arr = {123,321,12321,123,33,22,11,2132};
Stream<Integer> stream = Arrays.stream(arr);
stream.skip(3).forEach(System.out::println);
去重与排除

方 法描 述filter(Predicate p)接收 Lambda, 从流中排除某些元素distinct()筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素

Integer[]  arr = {123,321,12321,123,33,22,11,2132};
Stream<Integer> stream = Arrays.stream(arr);
stream1.filter(num -> num > 100).forEach(System.out::println);Integer[]  arr = {123,321,12321,123,33,22,11,2132};
Stream<Integer> stream = Arrays.stream(arr);
stream1.distinct().forEach(System.out::println);

基于元素

方法描述
  1. allMatch(Predicate p)检查是否匹配所有元素, anyMatch(Predicate p)检查是否至少匹配一个元素
  2. noneMatch(Predicate p)检查是否没有匹配所有元素
  3. findFirst()返回第一个元素
  4. findAny()返回当前流中的任意元素
  5. count()返回流中元素总数
  6. max(Comparator c)返回流中最大值
  7. min(Comparator c)返回流中最小值
  8. forEach(Consumer c)内部迭代 (使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)
Integer[]  arr = {123,321,12321,123,33,22,11,2132};
Stream<Integer> stream = Arrays.stream(arr);
System.out.println(stream.allMatch(num -> num > 100));
​
stream = Arrays.stream(arr);
System.out.println(stream.noneMatch(num -> num < 100));
​
stream = Arrays.stream(arr);
System.out.println(stream.anyMatch(num -> num > 100));
​
stream = Arrays.stream(arr);
System.out.println(stream.max(Integer::compare));

收集

那么对元素处理完成之后呢?Stream实际上不是很常用。我们还是希望能将Stream转化成list更好。所以Stream也对这个东西处理。直接调用就行

Integer[]  arr = {123,321,12321,123,33,22,11,2132};
Stream<Integer> stream = Arrays.stream(arr);
List<Integer> list = stream.sorted(Integer::compareTo).toList();

除此之外还有

  • toList将结果保存为List
  • toSet将结果保存为Set
  • toMap将结果保存为Map

实战

小明从Radis、MySQL、内存中,分别得到三个员工列表。小明需要将这三个列表中的数据进行去重、对工资进行排序、只输出工资大于1000的前3个并得到一个列表。请问如何?

可以想到。如果没有Stream的话每一步都是不断的循环。所以Steam的优越性就出来啦; )

Employee employee1 = new Employee(1, 1000.00);
Employee employee2 = new Employee(2, 1200.00);
Employee employee3 = new Employee(3, 1030.00);
Employee employee4 = new Employee(4, 1004.00);
Employee employee5 = new Employee(5, 1100.00);
Employee employee6 = new Employee(6, 1020.00);
Employee employee7 = new Employee(7, 1004.00);
Employee employee8 = new Employee(8, 10010.00);
Employee employee9 = new Employee(9, 21000.00);List<Employee> employees1 = new ArrayList<>();
employees1.add(employee1);
employees1.add(employee2);
employees1.add(employee3);
employees1.add(employee4);List<Employee> employees2 = new ArrayList<>();
employees2.add(employee5);
employees2.add(employee6);
employees2.add(employee7);
employees2.add(employee8);List<Employee> employees3 = new ArrayList<>();
employees3.add(employee9);
employees3.add(employee7);
employees3.add(employee5);
employees3.add(employee3);// 只有这里是具体操作
Stream<Employee> stream = Stream.concat(employees1.stream(),
        Stream.concat(employees2.stream(), employees3.stream()));
// 一步到位
stream.filter(employee -> employee.getSalary() > 1000)
        .distinct()
        .sorted((e1, e2) -> e2.getSalary().compareTo(e1.getSalary()))
        .limit(3)
        .toList()
        .forEach(System.out::println);

以上就是Java8 Stream的用法。如果对你有帮助,希望能给我点一个免费的赞,您的每一个点赞是我最大的动力。

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飛_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值