java8 peek_Java 8 Streams peek API

1. 简介

Stream API 为Java 处理数据提供了一种强大的替代方法。在这篇文章中,我们主要介绍Stream API 中一个经常被错误理解的方法peek()

2. 样例

假设我们有一个Person的流,我们想将Person的名字,年龄等信息打印到控制台。peek()方法的唯一参数是Consumer super T>看上去这就是我们想要的(不是唯一可以满足我们的):

Person 定义:

public class Person {

private String name;

private int age;

}

样例 1:

@Test

public void test_printInfoButNot() {

Person a = new Person("a", 18);

Person b = new Person("b", 23);

Person c = new Person("c", 34);

Stream persons = Stream.of(a, b, c);

persons.peek(System.out::println);

}

非常的遗憾,上面的代码没有任何输出。为了理解上面的代码为什么没有输出,我们快速的回顾一下与Stream生命周期相关的知识。

3. 中间操作 vs. 终止操作

流由三部分构成:数据源,一个或多个中间操作,一个或多个终止操作。

数据源:为流提供数据。

中间操作:依次获取数据并处理数据。所有的中间操作都是“懒操作”,也就是说在流开始工作之前,中间操作对流中的数据没有任何影响。

终止操作:流生命周期的结束,它可以触发流开始工作,中间操作也就会影响流中的数据。

4. 使用 peek()

在我们的例子中,peek()不起作用的原因是peek()是一个中间操作,而且我们没有提供一个终止操作。我们可以使用forEach(和peek()参数一样)来实现打印用户名和年龄的目标:

样例 2:

@Test

public void test_printInfo() {

Person a = new Person("a", 18);

Person b = new Person("b", 23);

Person c = new Person("c", 34);

Stream persons = Stream.of(a, b, c);

persons.forEach(System.out::println);

}

样例 2 输出结果如下:

Person{name='a', age=18}

Person{name='b', age=23}

Person{name='c', age=34}

按照Java团队的说法,peek()方法存在的主要目的是用调试,通过peek()方法可以看到流中的数据经过每个处理点时的状态。一个简单的样例如下:

样例 3:

@Test

public void test_peekDebug() {

Person a = new Person("a", 18);

Person b = new Person("b", 23);

Person c = new Person("c", 34);

Stream persons = Stream.of(a, b, c);

persons.filter(person -> person.getAge() < 30)

.peek(person -> System.out.println("filter " + person))

.map(person -> new Person(person.getName() + " map", person.getAge()))

.peek(person -> System.out.println("map " + person))

.collect(Collectors.toList());

}

样例 3 输出结果如下:

filter Person{name='a', age=18}

map Person{name='a map', age=18}

filter Person{name='b', age=23}

map Person{name='b map', age=23}

通过输出结果来看,peek()方法确实能够帮助我们观察传递给每个操作的数据。

除去用于调试,peek()在需要修改元素内部状态的场景也非常有用,比如我们想将所有Person的名字修改为大写,当然也可以使用map()和flatMap实现,但是相比来说peek()更加方便,因为我们并不想替代流中的数据。

样例 4 :

@Test

public void test_modifyInnerState() {

Person a = new Person("a", 18);

Person b = new Person("b", 23);

Person c = new Person("c", 34);

Stream persons = Stream.of(a, b, c);

persons.peek(person -> person.setName(person.getName().toUpperCase()))

.forEach(System.out::println);

}

样例 4 的输出结果如下:

Person{name='A', age=18}

Person{name='B', age=23}

Person{name='C', age=34}

5. 总结

在这篇文章中我们简单回顾了流的生命周期,组成部分以及peek()工作的原理。还介绍了peek()在调试和修改数据状态方面的应用。文中所有样例的代码可以从GitHub下载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值