玩转Stream流

在这里插入图片描述

1.流式思想

整体来看,流式思想类似于工厂车间的“生产流水线”。

在这里插入图片描述

Stream(流)是一个来自数据源的元素队列,是一个集合元素的函数模型,它并不是集合,也不是数据结构,其本身不存储任何元素(或其地址值)。

  • 元素是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。
  • 数据源流的来源:可以是集合,数组等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining:中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路(short-circuiting)。
  • 内部迭代:以前对集合遍历都是通过Iterator或者增强for的方式,显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式,流可以直接调用遍历方法。

2.获取流的方式

获取一个流非常简单,有以下几种常用的方式:

  • 所有的Collection集合都可以通过stream()默认方法获取流
  • Map集合体系下的接口,其K-V数据结构不符合流元素的单一特征,所以获取对应的流需要分key、value或entry等。
  • stream接口的静态方法of()可以获取数组对应的流,其中of()方法的参数为可变长参数。
//List集合获取流
List<String> list = new ArrayList<>();
Stream<String> listStream = list.stream();
//Set集合获取流
Set<String> set = new HashSet<>();
Stream<String> setStream = set.stream();
//Vector集合获取流
List<String> vector = new Vector<>();
Stream<String> vectorStream = vector.stream();
//Map集合获取流(key、value、entry)
Map<String, String> map = new HashMap<>();
Stream<String> keyStream = map.keySet().stream();
Stream<String> valueStream = map.values().stream();
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
//数组获取流
String[] stars = { "迪丽热巴", "古力娜扎", "刘亦菲", "景甜" };
Stream<String> arrayStream = Stream.of(stars);

3.常用方法

这些方法可以被分成两种:

  • 延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为延迟方法)
  • 终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似StringBuilder那样的链式调用。终结方法包括count()forEach()等方法。

举例:

首先创建一个人物的实体类,包括姓名、年龄、性别、门派、武力值几个属性。

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    //姓名
    private String name;
    //年龄
    private Integer age;
    //性别
    private Integer sex;
    //门派
    private String sect;
    //武力值
    private BigDecimal forceValue;
}

创建人物类集合作为数据源,用来测试接下来的API。

public static List<Person> getPersonList() {
    return Arrays.asList(
        new Person("张无忌", 18, 1, "明教", BigDecimal.valueOf(11000)),
        new Person("赵敏", 17, 0, "元朝", BigDecimal.valueOf(7000)),
        new Person("谢逊", 40, 1, "明教", BigDecimal.valueOf(8000)),
        new Person("张三丰", 99, 1, "武当派", BigDecimal.valueOf(12000)),
        new Person("灭绝师太", 60, 0, "峨嵋派", BigDecimal.valueOf(9000)),
        new Person("周芷若", 17, 0, "峨嵋派", BigDecimal.valueOf(10000)),
        new Person("成昆", 50, 1, "少林派", BigDecimal.valueOf(9000)));
    }

forEach方法:循环遍历

getPersonList().stream().forEach(System.out::println);
/*
Person(name=张无忌, age=18, sex=1, sect=明教, forceValue=11000)
Person(name=赵敏, age=17, sex=0, sect=元朝, forceValue=7000)
Person(name=谢逊, age=40, sex=1, sect=明教, forceValue=8000)
Person(name=张三丰, age=99, sex=1, sect=武当派, forceValue=12000)
Person(name=灭绝师太, age=60, sex=0, sect=峨嵋派, forceValue=9000)
Person(name=周芷若, age=17, sex=0, sect=峨嵋派, forceValue=10000)
Person(name=成昆, age=50, sex=1, sect=少林派, forceValue=9000)
*/

filter方法:过滤

List<Person> personFilter = getPersonList().stream().filter(x -> x.getAge() > 20).collect(Collectors.toList());
personFilter.stream().forEach(System.out::println);
/*
Person(name=谢逊, age=40, sex=1, sect=明教, forceValue=8000)
Person(name=张三丰, age=99, sex=1, sect=武当派, forceValue=12000)
Person(name=灭绝师太, age=60, sex=0, sect=峨嵋派, forceValue=9000)
Person(name=成昆, age=50, sex=1, sect=少林派, forceValue=9000)
*/

distinct方法:去重

//对数据源添加new Person("张无忌", 18, 1, "明教", BigDecimal.valueOf(11000))
List<Person> personList = getPersonList();
List<Person> personDistinct = personList.stream().distinct().collect(Collectors.toList());
personDistinct.stream().forEach(System.out::println);
/*
Person(name=张无忌, age=18, sex=1, sect=明教, forceValue=11000)
Person(name=赵敏, age=17, sex=0, sect=元朝, forceValue=7000)
Person(name=谢逊, age=40, sex=1, sect=明教, forceValue=8000)
Person(name=张三丰, age=99, sex=1, sect=武当派, forceValue=12000)
Person(name=灭绝师太, age=60, sex=0, sect=峨嵋派, forceValue=9000)
Person(name=周芷若, age=17, sex=0, sect=峨嵋派, forceValue=10000)
Person(name=成昆, age=50, sex=1, sect=少林派, forceValue=9000)
*/

sorted方法:排序

List<Person> personSorted = getPersonList().stream().sorted(Comparator.comparingInt(Person::getAge)).collect(Collectors.toList());
personSorted.stream().forEach(System.out::println);
/*
Person(name=赵敏, age=17, sex=0, sect=元朝, forceValue=7000)
Person(name=周芷若, age=17, sex=0, sect=峨嵋派, forceValue=10000)
Person(name=张无忌, age=18, sex=1, sect=明教, forceValue=11000)
Person(name=谢逊, age=40, sex=1, sect=明教, forceValue=8000)
Person(name=成昆, age=50, sex=1, sect=少林派, forceValue=9000)
Person(name=灭绝师太, age=60, sex=0, sect=峨嵋派, forceValue=9000)
Person(name=张三丰, age=99, sex=1, sect=武当派, forceValue=12000)
*/

limit方法:返回前n个元素

List<Person> personLimit = getPersonList().stream().sorted(Comparator.comparingInt(Person::getAge)).limit(2).collect(Collectors.toList());
personLimit.stream().forEach(System.out::println);
/*
Person(name=赵敏, age=17, sex=0, sect=元朝, forceValue=7000)
Person(name=周芷若, age=17, sex=0, sect=峨嵋派, forceValue=10000)
*/

skip方法:去除前n个元素

List<Person> personSkip = getPersonList().stream().sorted(Comparator.comparingInt(Person::getAge)).skip(2).collect(Collectors.toList());
personSkip.stream().forEach(System.out::println);
/*
Person(name=张无忌, age=18, sex=1, sect=明教, forceValue=11000)
Person(name=谢逊, age=40, sex=1, sect=明教, forceValue=8000)
Person(name=成昆, age=50, sex=1, sect=少林派, forceValue=9000)
Person(name=灭绝师太, age=60, sex=0, sect=峨嵋派, forceValue=9000)
Person(name=张三丰, age=99, sex=1, sect=武当派, forceValue=12000)
*/

map方法:映射

List<String> personMap = getPersonList().stream().map(Person::getName).collect(Collectors.toList());
personMap.stream().forEach(System.out::println);
/*
张无忌
赵敏
谢逊
张三丰
灭绝师太
周芷若
成昆
*/

flatMap方法:转换流

这里persons集合中的数据由逗号分割,使用split()方法进行分割后,得到的是Stream<String[]>字符串数组组成的流,然后使用flatMap()Arrays类静态方法stream()Stream<String[]>转为Stream<String>

List<String> persons = new ArrayList<>();
persons.add("张无忌,赵敏");
persons.add("周芷若,宋青书");
List<String> personFlatMap = persons.stream().map(x -> x.split(",")).flatMap(Arrays::stream).collect(Collectors.toList());
personFlatMap.stream().forEach(System.out::println);
/*
张无忌
赵敏
周芷若
宋青书
*/

allMatch方法:判断元素是否全部满足条件

boolean personAllMatch = getPersonList().stream().allMatch(x->x.getAge()>=18);
System.out.println(personAllMatch);
//false

anyMatch方法:判断元素是否任意一个元素满足条件

boolean personAnyMatch = getPersonList().stream().anyMatch(x -> x.getAge()==99);
System.out.println(personAnyMatch);
//true

noneMatch方法:判断元素是否不匹配条件

boolean personNoneMatch = getPersonList().stream().noneMatch(x -> x.getSect().equals("浑元形意太极门"));
System.out.println(personNoneMatch);
//true

concat方法:合并流

Stream<String> father = Stream.of("张翠山");
Stream<String> son = Stream.of("张无忌");
Stream<String> concatStream = Stream.concat(father, son);
concatStream.forEach(System.out::println);
//张翠山
//张无忌

findFirst方法:获取首元素

Optional<Person> optional = getPersonList().stream().findFirst();
System.out.println(optional.get());
//Person(name=张无忌, age=18, sex=1, sect=明教, forceValue=11000)

findAny方法:获取任意元素

Optional<Person> anyPerson = getPersonList().stream().findAny();
System.out.println(anyPerson.get());
//Person(name=张无忌, age=18, sex=1, sect=明教, forceValue=11000)

count方法:计数器

long count = getPersonList().stream().count();
System.out.println(count);
//7

maxBy方法和minBy方法:求最大、最小值

Optional<Person> maxByPerson = getPersonList().stream().collect(Collectors.maxBy(Comparator.comparingInt(Person::getAge)));
System.out.println(maxByPerson.get());
Optional<Person> minByPerson = getPersonList().stream().collect(Collectors.minBy(Comparator.comparingInt(Person::getAge)));
System.out.println(minByPerson.get());
//Person(name=张三丰, age=99, sex=1, sect=武当派, forceValue=12000)
//Person(name=赵敏, age=17, sex=0, sect=元朝, forceValue=7000)

summingInt方法和averagingInt方法:求和、求平均值

Integer sumAge = getPersonList().stream().collect(Collectors.summingInt(Person::getAge));
System.out.println(sumAge);
Double avgAge = getPersonList().stream().collect(Collectors.averagingInt(Person::getAge));
System.out.println(avgAge);
//301
//43.0

reduce方法:聚合

//实现聚合累加
BigDecimal personReduce = getPersonList().stream().map(Person::getForceValue).reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println(personReduce);
//66000

summarizingInt方法:同时求得统计数量、总和、最小值、最大值、平均值

IntSummaryStatistics intSummaryStatistics = getPersonList().stream().collect(Collectors.summarizingInt(Person::getAge));
System.out.println(intSummaryStatistics);
//IntSummaryStatistics{count=7, sum=301, min=17, average=43.000000, max=99}

joining方法:拼接

String personJoining = getPersonList().stream().map(Person::getName).collect(Collectors.joining(","));
System.out.println(personJoining);
//张无忌,赵敏,谢逊,张三丰,灭绝师太,周芷若,成昆

toMap方法:转换Map集合

Map<String, String> personToMap = getPersonList().stream().collect(Collectors.toMap(Person::getName, Person::getSect));
System.out.println(personToMap);
//{灭绝师太=峨嵋派, 张三丰=武当派, 谢逊=明教, 成昆=少林派, 周芷若=峨嵋派, 赵敏=元朝, 张无忌=明教}

grouping方法:分组

Map<Integer, List<Person>> personGrouping = getPersonList().stream().collect(Collectors.groupingBy(Person::getSex));
System.out.println(personGrouping);
/*
{0=[Person(name=赵敏, age=17, sex=0, sect=元朝, forceValue=7000), Person(name=灭绝师太, age=60, sex=0, sect=峨嵋派, forceValue=9000), Person(name=周芷若, age=17, sex=0, sect=峨嵋派, forceValue=10000)], 1=[Person(name=张无忌, age=18, sex=1, sect=明教, forceValue=11000), Person(name=谢逊, age=40, sex=1, sect=明教, forceValue=8000), Person(name=张三丰, age=99, sex=1, sect=武当派, forceValue=12000), Person(name=成昆, age=50, sex=1, sect=少林派, forceValue=9000)]}
*/

grouping方法和counting方法:实现分组统计数量

Map<String, Long> personCounting = getPersonList().stream().collect(Collectors.groupingBy(Person::getSect,Collectors.counting()));
System.out.println(personCounting);
//{元朝=1, 峨嵋派=2, 明教=2, 少林派=1, 武当派=1}

partitioningBy方法:分区

Map<Boolean, List<Person>> personPartitioningBy = getPersonList().stream().collect(Collectors.partitioningBy(x -> x.getAge() <= 18));
System.out.println(personPartitioningBy);
/*
{false=[Person(name=谢逊, age=40, sex=1, sect=明教, forceValue=8000), Person(name=张三丰, age=99, sex=1, sect=武当派, forceValue=12000), Person(name=灭绝师太, age=60, sex=0, sect=峨嵋派, forceValue=9000), Person(name=成昆, age=50, sex=1, sect=少林派, forceValue=9000)], true=[Person(name=张无忌, age=18, sex=1, sect=明教, forceValue=11000), Person(name=赵敏, age=17, sex=0, sect=元朝, forceValue=7000), Person(name=周芷若, age=17, sex=0, sect=峨嵋派, forceValue=10000)]}
*/
=99, sex=1, sect=武当派, forceValue=12000), Person(name=灭绝师太, age=60, sex=0, sect=峨嵋派, forceValue=9000), Person(name=成昆, age=50, sex=1, sect=少林派, forceValue=9000)], true=[Person(name=张无忌, age=18, sex=1, sect=明教, forceValue=11000), Person(name=赵敏, age=17, sex=0, sect=元朝, forceValue=7000), Person(name=周芷若, age=17, sex=0, sect=峨嵋派, forceValue=10000)]}
*/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

第二范式

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

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

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

打赏作者

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

抵扣说明:

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

余额充值