Stream流

1.Stream流介绍

Stream是Java 8提供的新功能,是对集合(Collection)对象功能的增强,能对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。 与Lambda 表达式结合,也可以提高编程效率、简洁性和程序可读性。

同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势

Stream<User> stream = userList.stream();  //串行
Stream<User> userStream = userList.parallelStream(); //并行

Stream的操作符大体分为两种:中间操作符和终止操作符

中间操作符:中间操作符在执行特定处理程序之后,数据依然可以传递给下一级的操作符

1.1 中间操作符

中间操作符主要包含8种:

  1. map(mapToInt,mapToLong,mapToDouble) 转换操作符,把比如A->B,这里默认提供了转int,long,double操作符
  2. flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作,比如把int[]{2,3,4}拍平,变成2,3,4也就是从原来的一个数据变成三个数据,这里默认拍平成int,double,long的操作符。
  3. limit限流操作,比如数据流中有10个,我只要出前三个就可以使用。
  4. distint去重操作,对重复元素去重,底层使用了equals方法。
  5. filter过滤操作,把不必要的数据过滤。
  6. peek挑出操作,对某些数据进行某些操作,如读取,编辑修改等。
  7. skip跳过操作,跳过某些元素
  8. sorted排序操作,对元素进行排序,前提是实现Comparable接口,也可以自定义比较器。

1.2 终止符

终止符包含8种:

  1. collect收集操作,将所有的数据收集起来,这个操作非常重要,官方提供的Collectors 提供了非常多收集器,可以说Stream的核心在于Collectors
  2. count统计操作,统计最终的数据个数
  3. findFirst,finfAny查找操作,查找第一个,查找任何一个返回的类型都是Optiona
  4. noneMatch,allMatch,anyMatch匹配操作,数据流中存在符合条件的元素,返回bool值
  5. min,max最值操作,需要自定义比较器,返回数据流中的最大值,最小值
  6. reduce规约操作,将整个流的值规约为一个值,count、min、max底层就是使用reduce。
  7. forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了。
  8. toArray 数组操作,将数据流的元素转换成数组。

终止操作符:数据经过中间加工操作,就轮到终止操作符上场了;终止操作符就是对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次。

2.stream流的创建方式

      2.1 使用Collection下的 stream() 和 parallelStream() 方法

List<String> list = new ArrayList<>();
Stream<String> Stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

       2.2 使用Arrays 中的 stream() 方法,将数组转成流

Integer[] nums = new Integer[10];
Stream<Integer> Stream = Arrays.stream(nums);

       2.3 使用Stream中的静态方法:of()、iterate()、generate()

Stream<Integer> Stream = Stream.of(1,2,3,4,5,6);
  
Stream<Integer> Stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
Stream2.forEach(System.out::println); // 0 2 4 6 8 10
  
Stream<Double> Stream3 = Stream.generate(Math::random).limit(2);
Stream3.forEach(System.out::println);

       2.4 使用 Pattern.splitAsStream() 方法,将字符串分隔成流

Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
stringStream.forEach(System.out::println);  //a b c d

3.Stream操作实例

        1.准备一个用户对象

package stream;

import java.util.Objects;

public class User {

    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer sex;
    private Double money;

    public User() {
    }

    public User(Integer id, String username, String password, Integer age, Integer sex, Double money) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
        this.sex = sex;
        this.money = money;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", money=" + money +
                '}';
    }

}

        2.集合里面放入对象

List<User> userList = new ArrayList<>();
userList.add(new User(1, "yykk", "111111", 34, 1, 34600d));
userList.add(new User(2, "祈福", "2222222", 24, 0, 883600d));
userList.add(new User(3, "小王", "3333333", 24, 1, 734090d));
userList.add(new User(4, "小楠", "4444444", 14, 0, 33400d));
userList.add(new User(5, "小张", "55555", 29, 1, 140000d));

    3.1 filter过滤某些元素

                查询用户年龄大于25岁的

 List<User> collect = userList.stream().filter(new Predicate<User>() {
            @Override
            public boolean test(User user) {
                return user.getAge() > 25;
            }
        }).collect(Collectors.toList());

                可以简写成下面这个

 List<User> collect5 = stream.filter(user -> user.getAge() > 25).collect(Collectors.toList()); 

    3.2 peek和map

          peek没返回值 

 Stream<T> peek(Consumer<? super T> action); //无返回值

          map有返回值

<R> Stream<R> map(Function<? super T, ? extends R> mapper);  //有返回值

             peek 实例:查询年龄大于25岁并且年龄加1岁

 List<User> collect1 = userList.stream().
                filter(user -> user.getAge() > 25).
                peek(u -> u.setAge(u.getAge()+1)).
                collect(Collectors.toList());
        System.out.println(collect1);

        map实例:查询年龄大于25岁并且年龄加1岁

 //年龄大于25岁的加1岁 map
        List<User> collect2 = userList.stream().filter(user -> user.getAge() > 25).
                map(user -> {
                    user.setAge(user.getAge() + 1);
                    return user;
                }).collect(Collectors.toList());
        System.out.println("==========");
        System.out.println(collect2);

peek和map的区别是什么?

  • peek和map区别:peek无返回值,map有返回值

  • peek你前面集合流化对象返回的是什么就是什么?map可以把stream返回值进行改变。我可以把集合中的对象改成map在返回。或者我只需要集合中某个一列的值。

比如下面的例子

        只返回用户的姓名

List<String> collect3 = userList.stream().map(user -> {
            return user.getUsername();
        }).collect(Collectors.toList());
for (String s : collect3) {
    System.out.println(s);
}
//输出结果
//yykk
//祈福
//小王
//小楠
//小张

        只返回用户的姓名和年龄(定义的map,返回的类型发生了改变)    除了定义map 也可以定义一个vo类

List<Map<String, Object>> collect4 = userList.stream().map(user -> {
            Map<String, Object> map = new HashMap<>();
            map.put("username", user.getUsername());
            map.put("age", user.getAge());
            return map;
        }).collect(Collectors.toList());

//输出结果
//{age=36, username=yykk}
//{age=24, username=祈福}
//{age=24, username=小王}
//{age=14, username=小楠}
//{age=31, username=小张}

        3.3 sorted排序

                用户根据年龄排序

List<User> collect = userList.stream().sorted(new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getAge() - o2.getAge();
            }
        }).collect(Collectors.toList());

//可以简写成
//List<User> collect = userList.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).collect(Collectors.toList());
for (User user : collect) {
      System.out.println(user);
}

       3.4 distinct 去重

        去重,去重重复的用户对象 去重时一定重新equals和hashCode。但是如果两个用户之间比较是否相等,用户对象只需要重写equals方法

               重写equals和hashcode

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id) &&
                Objects.equals(username, user.username) &&
                Objects.equals(password, user.password) &&
                Objects.equals(age, user.age) &&
                Objects.equals(sex, user.sex) &&
                Objects.equals(money, user.money);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username, password, age, sex, money);
    }

        3.5 limit 限流操作

                比如用户数据有5个 我只取3个

 List<User> collect2 = userList.stream()
                .limit(3)
                .collect(Collectors.toList());
 for (User user : collect2) {
      System.out.println(user);
}

         3.6 skip 跳过操作,跳过某些元素

                  跳过三条数据再取数据  就是有5条数据的话 跳过了3条,就只能取最后两条了

List<User> collect2 = userList.stream()
                .skip(3)
                .collect(Collectors.toList());
for (User user : collect2) {
     System.out.println(user);
}

              limit和skip组合可以简单的实现分页

 //分页设计
Integer pageSize = 2;//每页几条
Integer pageNo = 1; //第几页

Integer skip = (pageNo-1)*pageSize;
//skip(2) 代表跳过两个用户再取数据
List<User> collect2 = userList.stream()
            .skip(skip)
            .limit(pageSize)
            .collect(Collectors.toList());
for (User user : collect2) {
     System.out.println(user);
}

           3.7  mapToInt

int sum = userList.stream().mapToInt(user11 -> user11.getAge()).sum(); //年龄和
double average = userList.stream().mapToInt(user11 -> user11.getAge()).average().getAsDouble(); //平均值
int min = userList.stream().mapToInt(user11 -> user11.getAge()).min().getAsInt(); //最小值
int max = userList.stream().mapToInt(user11 -> user11.getAge()).max().getAsInt(); //最小值

    终止操作

         3.8 max min 最大最小值

                年龄最大的用户

User user2 = userList.stream().max(((o1, o2) -> o1.getAge() - o2.getAge())).get();
System.out.println(user2);

               用户最大的年龄 利用map转化输出的流形式 

Integer maxAge = userList.stream().map(user3 -> user3.getAge()).max(((o1, o2) -> o1 - o2)).get();
System.out.println(maxAge);

         3.9 count 数量大小

long count1 = userList.stream().count();
System.out.println(count1);

        3.10 findFirst 取出集合中第一个元素,findAny 取出集合中任意一个数据

                取出用户集合中的第一个用户

Optional<User> user = userList.stream().distinct().findFirst();
System.out.println(user.get());

                取出用户集合中的任意一个用户 

                 注意:取出集合中的任意一个元素,需要使用并行流,串行流一直取出的都是第一个元素

//取出集合中的随意一条数据 需要并行流
User user1 = userList.parallelStream().distinct().findAny().get();
System.out.println(user1);

        3.11 anyMatch  只要有一个数据满足条件就是true

                 allMatch  必须所有条件都满足 才可以是true

                 noneMatch  和allMatch相对的

        所有用户年龄大于16岁,才可以是true

boolean b2 = userList.stream().anyMatch(user1 -> user1.getAge() > 16);
System.out.println(b2);

        所有人年龄大于16岁,是false

 boolean b = userList.stream().noneMatch(new Predicate<User>() {
            @Override
            public boolean test(User user) {
                return user.getAge() > 16;
            }
        });
//简写成
boolean b3 = userList.stream().noneMatch(user1 -> user1.getAge() > 16);

        只要有一个人的年龄大于16岁就是true

boolean b2 = userList.stream().anyMatch(user1 -> user1.getAge() > 16);
System.out.println(b2);

        3.12 Collectors.groupingBy 分组

         根据用户性别进行分组 

Map<Integer, List<User>> collect = userList.stream().collect(Collectors.groupingBy(User::getSex));
List<User> users = collect.get(0);

        Collectors.partitioningBy 根据条件划分

                用户年龄大于16岁,和小于等于16岁分成两组

Map<Boolean, List<User>> collect1 = userList.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 16));
List<User> aTrue = collect1.get(true);

本文章根据飞哥视频总结出来

b站视频:【学相伴飞哥】Java新特性-stream流初步学习_哔哩哔哩_bilibili

        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值