Java数据处理利器-Stream流编程入门

什么是流

Java 8 API添加了一个新的抽象称为流Stream,其可以以一种声明式的方式处理数据。它将基础操作链接起来,能完成复杂的数据处理流水线,并提供了透明的并行处理机制。

Stream流的组成

  • 数据源
  • 中间操作
  • 终端操作

一图胜千言,从整体上了解下相关的内容

在这里插入图片描述
流与集合的区别:

  • 流相对于是时间上的集合,得到的是某一时刻的数据(面向计算)
  • 集合相对于是空间上的集合,需要真实的存储(面向存储)
  • 流只能遍历一次,集合可以反复操作
  • 流是内部迭代,集合是外部迭代

怎么使用流编程

下面将对流编程的操作和构建一一进行演示

创建一个实体类User方便我们使用

	class User {
        private Integer userId;
        private String userName;
        private String password;

        public User(Integer userId, String userName, String password) {
            this.userId = userId;
            this.userName = userName;
            this.password = password;
        }

        public Integer getUserId() {
            return userId;
        }

        public String getUserName() {
            return userName;
        }

        public String getPassword() {
            return password;
        }
    }

创建一个集合,作为我们数据操作的数据

		List<User> list = new ArrayList<User>() {
            {
                add(new User(5,"ckhhh", "123123"));
                add(new User(1,"zhangsan", "1232312"));
                add(new User(3,"lisi", "000000"));
                add(new User(2,"lisi", "4324324"));
                add(new User(4,"wangwu", "99999"));


            }
        };

中间操作

  1. 无状态的
  • filter使用
		/**
         * filter使用 按照指定条件过滤集合
         */
		  list.stream().
		             filter(user -> user.getUserName().equals("lisi")).
		             forEach(user ->
		                     System.out.println(JSON.toJSONString(user, true)));

打印用户名为lisi的用户的信息,结果如下:

{
	"password":"000000",
	"userId":3,
	"userName":"lisi"
}
{
	"password":"4324324",
	"userId":2,
	"userName":"lisi"
}
  • map使用
		/**
         * map使用 从一种类型转化为另一种类型的集合,user->string
         */
        list.stream().
                map(user -> user.getUserName()).
                forEach(user ->
                        System.out.println(JSON.toJSONString(user, true)));

使用map将集合分割,只获取所有用户并打印,结果如下:

"ckhhh"
"zhangsan"
"lisi"
"lisi"
"wangwu"
  • flatMap操作
   		/**
         * flatMap操作 接收一个元素,返回一个新的流(将对象转换为流操作)
         */
        list.stream()
                .flatMap(user -> Arrays.stream(user.getUserName().split("")))
                .forEach(user ->
                        System.out.println(JSON.toJSONString(user, true)));

使用flatMap将集合变为新的流:将名字分割成字符,然后打印,结果如下:

"c"
"k"
"h"
"h"
"h"
"z"
"h"
"a"
"n"
"g"
"s"
"a"
"n"
"l"
"i"
"s"
"i"
"l"
"i"
"s"
"i"
"w"
"a"
"n"
"g"
"w"
"u"
  • peek操作
		 /**
         * peek 中间操作 无状态的 操作完后流还可以使用  foreach使用后就不能用了
         * peek和foreach交替打印
         */
        list.stream()
                .peek(user -> System.out.println(user.getUserName()))
                .forEach(user ->
                        System.out.println(JSON.toJSONString(user, true)));

打印用户名,因为是无状态的,所以会执行完一下peek后执行一下foreach中的打印,结果如下

ckhhh
{
	"password":"123123",
	"userId":5,
	"userName":"ckhhh"
}
zhangsan
{
	"password":"1232312",
	"userId":1,
	"userName":"zhangsan"
}
lisi
{
	"password":"000000",
	"userId":3,
	"userName":"lisi"
}
lisi
{
	"password":"4324324",
	"userId":2,
	"userName":"lisi"
}
wangwu
{
	"password":"99999",
	"userId":4,
	"userName":"wangwu"
}
  1. 有状态的
  • sort操作
 		/**
         * sort操作,对数据按照规则排序
         * sorted是有状态的  所以会等peek结束之后再操作
         * peek和foreach就不会再交替打印了
         */
        list.stream()
                .peek(user -> System.out.println(user.getUserName()))
                .sorted(Comparator.comparing(User::getUserId))
                .forEach(user ->
                        System.out.println(JSON.toJSONString(user, true)));

排序后打印,是有状态的,所以必须所有peek执行完了后才能执行,根据userId升序排列,结果如下:

ckhhh
zhangsan
lisi
lisi
wangwu
{
	"password":"1232312",
	"userId":1,
	"userName":"zhangsan"
}
{
	"password":"4324324",
	"userId":2,
	"userName":"lisi"
}
{
	"password":"000000",
	"userId":3,
	"userName":"lisi"
}
{
	"password":"99999",
	"userId":4,
	"userName":"wangwu"
}
{
	"password":"123123",
	"userId":5,
	"userName":"ckhhh"
}
  • distinct操作
/**
         * distinct操作  去除重复
         */
        list.stream()
                .map(user -> user.getUserName())
                .distinct()
                .forEach(user ->
                        System.out.println(JSON.toJSONString(user, true)));

去除用户名中的重复项后打印用户名,结果如下:

"ckhhh"
"zhangsan"
"lisi"
"wangwu"
  • skip操作
		/**
         *  skip过滤掉前三条
         */
        list.stream()
                .sorted(Comparator.comparing(user ->user.getUserId()))
                .skip(3)
                .forEach(user ->
                        System.out.println(JSON.toJSONString(user, true)));

按id升序排序后,跳过前三条,从第四条开始打印,结果如下:

{
	"password":"99999",
	"userId":4,
	"userName":"wangwu"
}
{
	"password":"123123",
	"userId":5,
	"userName":"ckhhh"
}
  • limit操作
		 /**
         * limit操作  获取前三条
         */
        list.stream()
                .sorted(Comparator.comparing(user ->user.getUserId()))
                .limit(3)
                .forEach(user ->
                        System.out.println(JSON.toJSONString(user, true)));

按id升序排列后,打印前三条,结果如下:

{
	"password":"1232312",
	"userId":1,
	"userName":"zhangsan"
}
{
	"password":"4324324",
	"userId":2,
	"userName":"lisi"
}
{
	"password":"000000",
	"userId":3,
	"userName":"lisi"
}

终端操作

  1. 短路的操作
  • allMatch操作
		/**
         * allMatch 使用:是否全部满足终端操作,短路的操作
         * 如果发现了不匹配的  就不会继续执行了,peek中打印的数据打不符合的就停止了
         */
        boolean b = list.stream()
                .peek(user -> System.out.println(user.getUserId()))
                .allMatch(user->user.getUserId()> 2);
        System.out.println(b);

判断是否所有的用户id都大于2,一旦发现小于等于2的就返回false,结果如下

5
1
false
  • anyMatch操作
		/**
         * anyMatch使用  :只要有满足的,就返回true
         * 短路的  找到一个符合的就返回true
         */
        boolean c = list.stream()
                 .peek(user -> System.out.println(user.getUserId()))
                .anyMatch(user->user.getUserId()> 2);
        System.out.println(c);

判断是否有用户id大于2,一旦发现大于2的就返回true,结果如下

5
true
  • noneMatch操作
		/**
         * noneMatch使用:所有的都没匹配上 返回true
         * 短路的,找到一个符合的就返回false
         */
        boolean d = list.stream()
                 .peek(user -> System.out.println(user.getUserId()))
                .noneMatch(user->user.getUserId()> 2);
        System.out.println(d);

判断是否没有用户id大于2,一旦发现大于2的就返回false,结果如下:

5
false
  • findFirst操作
 		/**
         * findFirst:获取第一个对象
         * 短路的  获取了就返回
         */
        Optional<User> first = list.stream()
                .findFirst();
        System.out.println(JSON.toJSONString(first.get(), true));

返回第一个对象,结果如下

{
	"password":"123123",
	"userId":5,
	"userName":"ckhhh"
}
  • findAny操作
		 /**
         * findAny找到任何一个就返回
         * 并行操作时findAny会更快,可能会随机匹配 如果串行一致
         */
        Optional<User> first1 = list.stream()
                .findAny();
        System.out.println(JSON.toJSONString(first1.get(), true));

返回任意一个对象,在串行下和返回第一个对象一样,在并行下就是随机的,结果如下:

{
	"password":"123123",
	"userId":5,
	"userName":"ckhhh"
}
  1. 非短路操作
  • max操作
		 /**
         * max操作:获取最大值
         */
        OptionalDouble max = list.stream()
                .mapToDouble(User::getUserId)
                .max();
        System.out.println(max.getAsDouble());

将用户id列分割出来,将值转为doble,返回最大值,结果如下:

5.0
  • min操作
		/**
         * min操作:获取最小值
         */
        OptionalDouble min = list.stream()
                .mapToDouble(User::getUserId)
                .min();
        System.out.println(min.getAsDouble());

将用户id列分割出来,将值转为doble,返回最小值,结果如下:

1.0
  • count操作
 		/**
         * count操作:获取元素的个数
         */
        long count = list.stream()
                .count();
        System.out.println(count);

统计元素个数,结果如下:

5
  • collect操作
		/**
         *  集合收集器
         */
        List<User> result = list.stream()
                .filter(user -> user.getUserId() > 2)
                .collect(Collectors.toList());
        System.out.println(JSON.toJSONString(result, true));

将id大于2的元素重新写入集合,打印结果如下:

[
	{
		"password":"123123",
		"userId":5,
		"userName":"ckhhh"
	},
	{
		"password":"000000",
		"userId":3,
		"userName":"lisi"
	},
	{
		"password":"99999",
		"userId":4,
		"userName":"wangwu"
	}
]

        /**
         *  分组收集器
         */
        Map<String, List<User>> group = list.stream()
                .collect(Collectors.groupingBy(
                        user -> user.userName));
        System.out.println(JSON.toJSONString(group, true));

将元素按用户名分组后打印,结果如下:

{
	"lisi":[
		{
			"password":"000000",
			"userId":3,
			"userName":"lisi"
		},
		{
			"password":"4324324",
			"userId":2,
			"userName":"lisi"
		}
	],
	"ckhhh":[
		{
			"password":"123123",
			"userId":5,
			"userName":"ckhhh"
		}
	],
	"zhangsan":[
		{
			"password":"1232312",
			"userId":1,
			"userName":"zhangsan"
		}
	],
	"wangwu":[
		{
			"password":"99999",
			"userId":4,
			"userName":"wangwu"
		}
	]
}

        /**
         * 分区收集器
         * 分为大于2和小于等于2两部分
         */
        Map<Boolean, List<User>> partition = list.stream()
                .collect(Collectors.partitioningBy(user -> user.getUserId() > 2));

        System.out.println(JSON.toJSONString(partition, true));

将元素按id大于2位标准分为两个区后进行打印,结果如下:

{false:[
		{
			"password":"1232312",
			"userId":1,
			"userName":"zhangsan"
		},
		{
			"password":"4324324",
			"userId":2,
			"userName":"lisi"
		}
	],true:[
		{
			"password":"123123",
			"userId":5,
			"userName":"ckhhh"
		},
		{
			"password":"000000",
			"userId":3,
			"userName":"lisi"
		},
		{
			"password":"99999",
			"userId":4,
			"userName":"wangwu"
		}
	]
}

构建流

  • 由数值直接构建流
public void steamFromValue() {
    Stream stream = Stream.of(1, 2, 3, 4, 5);

    stream.forEach(System.out::println);
}

运行结果如下:

1
2
3
4
5
  • 由数组构建流
 public void streamFromArray() {
        int[] num = new int[]{1, 2, 3, 4, 5};
        Arrays.stream(num)
                .forEach(System.out::println);
  }

运行结果如下:

1
2
3
4
5
  • 通过文件构建流
public void streamFromFile() throws IOException {
        Stream<String> stream = Files.lines(Paths.get("F:/QQ下载/FileServer.java"));
        stream.forEach(System.out::println);
}

运行结果如下(部分)

package com.demo.lambda;

import java.io.*;

/**
 * 〈文件服务类〉
 *
 * @author Chkl
 * @create 2020/4/20
 * @since 1.0.0
 */
public class FileServer {

    /**
     * 通过url获取本地文件内容
     *
     * @param url
     * @param fileConsumer
     */
    public void fileHandler(String url, FileConsumer fileConsumer) throws IOException {
	..............
	...............
  • 通过函数生成流(无限流)
public void streamFromFunction() {
        //参数: 初始值,规则(从0开始生成偶数)
        Stream<Integer> stream = Stream.iterate(0, n -> n + 2);
        stream.limit(100)
                .forEach(System.out::println);
        //随机生成
        Stream<Double> stream2 = Stream.generate(Math::random);
        stream2.limit(100)
                .forEach(System.out::println);

}

第一种运行结果如下(部分):

0
2
4
6
8
10
12
14
16
18
20
22
24

第二种运行结果如下(部分):

0.28047181698982915
0.3366379505477519
0.6314896823002529
0.4202209521644461
0.8362832087391032
0.7025533309035066
0.49208504805565545
0.18517793464530763
0.37580620856029856
0.8888281509032474
0.8399345540793907
0.6470816912713735
0.9842389606178953
0.5166615554196825
0.035214233629631164

通过以上的学习,可以基本的掌握Stream流常用的一些操作和构建方便了,具体业务需要使用到的方法在使用时再去了解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值