Stream API 真香

前言

在没有接触Stream API之前,在遇到集合类操作,比如提取集合中满足条件的某些元素或者对两个集合进行数据对
比和筛选等,总是避免不了各种循环操作,代码量总是很大。我就在想既然集合类一般都是存贮的一种类型的数据
类似数据库中的一张表,每个对象的就是一条数据,每个属性就是一个字段,既然针对数据库表有SQL这种语言来
进行数据的筛选操作,那么在java代码中有没有类似的API来处理对集合类型中数据的处理呢?后来发现还真有,这
就是Stream API.

Stream是什么

是一种数据渠道,用来操作数据源比如集合,数组等。
Stream只是一种操作,本身并不会修改原有的数据源。而是返回新的Stream。
Stream的操作是延迟的。

如何使用Stream

1 创建stream

 1.1  通过Collection集合中的stream()活parallestream()。
        List<String> lists = new ArrayList<>();
        list.stream();
        list.parallelStream()
 1.2  通过Arrays中的静态方法stream()获取数组流。
        Student[] studentss = new Student[5];
        Stream<Student> streams = Arrays.stream(studentss);
 1.3  通过stream类中的ofStream()方法。
        Stream<String> stringStream = Stream.of("yyf", "zrf", "zxc");

2 中间操作

2.1	筛选与切片
	filter    --接收Lambda,从流中排除某些元素。
	limit     --从流中选中几条。
	distinct  --通过hashCode()和equals()方法去重。
	skip(n)   --返回一个扔掉了前n个元素的流。

@Slf4j
public class TestStream {
    public static void main(String[] args) {
        List<User> list = Arrays.asList(
                new User(32, "yyf", "河南"),
                new User(34, "abc","北京"),
                new User(65, "yyf", "天津"),
                new User(31, "ewe","上海"),
                new User(22, "yyf", "广东"),
                new User(32, "yyf", "河南")
        );
        log.info("打印出年龄大于32的用户");
        list.stream().filter(e->e.getAge().compareTo(32)>=0).forEach(System.out::println);
        log.info("打印出前三个用户");
        list.stream().limit(3L).forEach(System.out::println);
        log.info("跳过前三个用户");
        list.stream().skip(3L).forEach(System.out::println);
        log.info("去重相同用户");
        list.stream().distinct().forEach(System.out::println);
        log.info("合并两个stream  ======union all");
        Stream.concat(list.stream().limit(3L),list.stream().skip(4L)).forEach(System.out::println);
    }
}
输出如下:
[main] INFO com.sjbl.TestStream - 打印出年龄大于32的用户
User(age=32, name=yyf, birthAddress=河南)
User(age=34, name=abc, birthAddress=北京)
User(age=65, name=yyf, birthAddress=天津)
User(age=32, name=yyf, birthAddress=河南)
[main] INFO com.sjbl.TestStream - 打印出前三个用户
User(age=32, name=yyf, birthAddress=河南)
User(age=34, name=abc, birthAddress=北京)
User(age=65, name=yyf, birthAddress=天津)
[main] INFO com.sjbl.TestStream - 跳过前三个用户
User(age=31, name=ewe, birthAddress=上海)
User(age=22, name=yyf, birthAddress=广东)
User(age=32, name=yyf, birthAddress=河南)
[main] INFO com.sjbl.TestStream - 去重相同用户
User(age=32, name=yyf, birthAddress=河南)
User(age=34, name=abc, birthAddress=北京)
User(age=65, name=yyf, birthAddress=天津)
User(age=31, name=ewe, birthAddress=上海)
User(age=22, name=yyf, birthAddress=广东)
[main] INFO com.sjbl.TestStream - 合并两个stream  ======union all
User(age=32, name=yyf, birthAddress=河南)
User(age=34, name=abc, birthAddress=北京)
User(age=65, name=yyf, birthAddress=天津)
User(age=22, name=yyf, birthAddress=广东)
User(age=32, name=yyf, birthAddress=河南)
2.2 映射操作
<R> Stream<R> map(Function<? super T,? extends R> mapper)返回由给定函数应用于此流的元素的结果组成的流。
	    log.info("给每一个年龄都加上10");
        list.stream().map(e -> e.getAge() + 10).forEach(System.out::println);
        log.info("将名称提取出来");
        list.stream().map(User::getName).forEach(System.out::println);
        int ageSum = list.stream().mapToInt(User::getAge).sum();
        System.out.println("年龄总和为:" + ageSum);
        double ageAve = list.stream().mapToInt(User::getAge).average().getAsDouble();
        System.out.println("年龄平均值为:" + ageAve);
        int ageMax = list.stream().mapToInt(User::getAge).max().getAsInt();
        System.out.println("年龄最大值为:" + ageMax);
        int ageMin = list.stream().mapToInt(User::getAge).min().getAsInt();
        System.out.println("年龄最大值为:" + ageMin);
输出如下:
[main] INFO com.sjbl.TestStream - 给每一个年龄都加上10
42
44
75
41
32
42
[main] INFO com.sjbl.TestStream - 将名称提取出来
yyf
abc
yyf
ewe
yyf
yyf
年龄总和为:216
年龄平均值为:36.0
年龄最大值为:65
年龄最大值为:22
2.3排序操作
        log.info("按年龄升序排方式一");
        list.stream().sorted(Comparator.comparing(User::getAge)).forEach(System.out::println);
        log.info("按年龄升序排方式二");
        list.stream().sorted((a,b)->a.getAge().compareTo(b.getAge())).forEach(System.out::println);
        log.info("按年龄降序排");
        list.stream().sorted((a,b)->b.getAge().compareTo(a.getAge())).forEach(System.out::println);
输出如下:
[main] INFO com.sjbl.TestStream - 按年龄升序排方式一
User(age=22, name=yyf, birthAddress=广东)
User(age=31, name=ewe, birthAddress=上海)
User(age=32, name=yyf, birthAddress=河南)
User(age=32, name=yyf, birthAddress=河南)
User(age=34, name=abc, birthAddress=北京)
User(age=65, name=yyf, birthAddress=天津)
[main] INFO com.sjbl.TestStream - 按年龄升序排方式二
User(age=22, name=yyf, birthAddress=广东)
User(age=31, name=ewe, birthAddress=上海)
User(age=32, name=yyf, birthAddress=河南)
User(age=32, name=yyf, birthAddress=河南)
User(age=34, name=abc, birthAddress=北京)
User(age=65, name=yyf, birthAddress=天津)
[main] INFO com.sjbl.TestStream - 按年龄降序排
User(age=65, name=yyf, birthAddress=天津)
User(age=34, name=abc, birthAddress=北京)
User(age=32, name=yyf, birthAddress=河南)
User(age=32, name=yyf, birthAddress=河南)
User(age=31, name=ewe, birthAddress=上海)

3 终止操作

3.1 查找与匹配
allMatch--检查是否匹配所有元素
anyMatch--检查是否匹配至少一个元素
noneMatch --检查是否没有匹配所有元素
findFirst --返回第一个元素
findAny --返回当前流中的任意元素
        boolean abcResult = list.stream().anyMatch(e -> e.getName().equals("abc"));
        log.info("集合中是否有一个名称为abc:" + abcResult);
        boolean addSizeResult = list.stream().allMatch(e -> e.getBirthAddress().toCharArray().length == 2);
        log.info("集合中是否所有人地址都是两个字符:" + addSizeResult);
        boolean noZheJiang = list.stream().noneMatch(e -> e.getBirthAddress().equals("浙江"));
        log.info("集合中是否所有人都不来自浙江:" + noZheJiang);
        Optional<User> any = list.stream().findAny();
        log.info("集合中随机抽取一个元素:" + any.toString());
输出如下:
[main] INFO com.sjbl.TestStream - 集合中是否有一个名称为abc:true
[main] INFO com.sjbl.TestStream - 集合中是否所有人地址都是两个字符:true
[main] INFO com.sjbl.TestStream - 集合中是否所有人都不来自浙江:true
[main] INFO com.sjbl.TestStream - 集合中随机抽取一个元素:Optional[User(age=32, name=yyf, birthAddress=河南)]
3.2 收集
		List<Integer> ageList = list.stream().map(User::getAge).collect(Collectors.toList());
        log.info("ageList为" + ageList.toString());
        Set<Integer> ageSet = list.stream().map(User::getAge).collect(Collectors.toSet());
        log.info("ageSet为" + ageSet.toString());
        Set<Integer> ageHashSet = list.stream().map(User::getAge).collect(Collectors.toCollection(HashSet::new));
        log.info("ageHashSet为" + ageHashSet.toString());
输出如下:
[main] INFO com.sjbl.TestStream - ageList为[32, 34, 65, 31, 22, 32]
[main] INFO com.sjbl.TestStream - ageSet为[32, 65, 34, 22, 31]
[main] INFO com.sjbl.TestStream - ageHashSet为[32, 65, 34, 22, 31]        
3.3 分组
   Map<String, List<User>> addMap = list.stream().collect(Collectors.groupingBy(User::getBirthAddress));
        log.info("按照出生地分组" + addMap.toString());
        Map<String, Map<String, List<User>>> addAndNameMap = list.stream()
                .collect(Collectors.groupingBy(User::getBirthAddress, Collectors.groupingBy(a->{
                    if(a.getAge()<=25){
                        return "少年";
                    }else if(a.getAge()>25&&a.getAge()<=50){
                        return "壮年";
                    }else {
                        return "老年";
                    }
                })));
        log.info("按照出生地和年龄段分组" + addAndNameMap.toString());
输出如下:
[main] INFO com.sjbl.TestStream - 按照出生地分组{上海=[User(age=31, name=ewe, birthAddress=上海)], 广东=[User(age=22, name=yyf, birthAddress=广东)], 天津=[User(age=65, name=yyf, birthAddress=天津)], 河南=[User(age=32, name=yyf, birthAddress=河南), User(age=32, name=yyf2, birthAddress=河南)], 北京=[User(age=34, name=abc, birthAddress=北京)]}
[main] INFO com.sjbl.TestStream - 按照出生地和年龄段分组{上海={壮年=[User(age=31, name=ewe, birthAddress=上海)]}, 广东={少年=[User(age=22, name=yyf, birthAddress=广东)]}, 天津={老年=[User(age=65, name=yyf, birthAddress=天津)]}, 河南={壮年=[User(age=32, name=yyf, birthAddress=河南), User(age=32, name=yyf2, birthAddress=河南)]}, 北京={壮年=[User(age=34, name=abc, birthAddress=北京)]}}        

总结

	结合上篇文章中对于sql的使用建议,在SQL中尽量避免复杂的查询,如果需要关联多个表的数据,可以使用单表
查出几个较为粗略的List,然后在java代码中通过Stream API来进行真正的结果的“封装拼接”。既避免了复杂
查询时导致的数据库的查询等待,又通过使用Stream API避免了java代码中的令人眼花缭乱的各种循环代码。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值