使用Stream流写出优雅的高质量代码

前言

我们在开发中会大量的用到集合,少不了对集合进行一些操作,如何优雅的遍历集合,操作集合,不仅能体现出代码的质量,更能体现出程序员本身对自我的要求。
在这里插入图片描述

一、Stream初体验

例如我们此时有这样的一个需求:把所有已“邓”字开头的元素,并且长度超过3的打印出来。

  • 常规方法实现
public class StreamDemo1 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"鹿晗","邓紫棋","吴青峰","邓超","许嵩");

        // 1.把所有以“邓”为开头的元素存储到新集合中
        List<String> list1 = new ArrayList<>();
        for (String name : list) {
             if (name.startsWith("邓")){
                 list1.add(name);
             }
        }

        // 2.把邓开头的,长度为3的元素再存储到新集合中
        List<String> list2 = new ArrayList<>();
        for (String name : list1) {
            if (name.length() == 3){
                list2.add(name);
            }
        }

        // 3.遍历打印最终结果
        for (String s : list2) {
            System.out.println(s);
        }
    }
}
  • 使用Stream流实现
public class StreamDemo1 {
    public static void main(String[] args) {

        List<String> list = new ArrayList<>();
        Collections.addAll(list,"鹿晗","邓紫棋","吴青峰","邓超","许嵩");
        list.stream().filter(name->name.startsWith("邓")).filter(name->name.length()==3).forEach(name-> System.out.println(name));
    }
}

经过对比,是不是眼前一亮,原本那么多行的代码,一下被删减了好多!其实我在刚参加工作的时候,就真的惊了,也确实感受到了和别人差距。我就是第一种方法实现的,而看到别人写的代码甚至都不理解!
那么接下来,我们就好好学习一下吧~

二、Stream流的使用

  1. 先得到一条Stream流(流水线),并把数据放上去
  2. 使用中间方法对流水线上的数据进行操作
  3. 使用终结方法对流水线上的数据进行操作

2.1 获取流水线

数据类型方法说明
单列集合default Streamstream()Collection中的默认方法
双列集合无法直接使用Stream流
数组public staticStreamstream(T[]array)Arrays工具类中的静态方法
一堆零散数据public staticStreamof(T…values)Stream接口中的静态方法
// 1.单列集合获取Stream流
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"张三","李四","王五","张三丰");
        // 获取一条流水线,并把集合中的数据放到流水线上
        Stream<String> stream = list.stream();

// 2.双列集合获取Stream流
        Map<String,Integer> hm = new HashMap<>();
        // 2.1 添加数据
        hm.put("aaa",111);
        hm.put("bbb",222);
        hm.put("ccc",333);

        // 2.2 获取stream流——键
        Stream<String> stream = hm.keySet().stream();

        // 2.3 第二种获取stream流——键值对
        Stream<Map.Entry<String, Integer>> stream1 = hm.entrySet().stream();

// 3.数组获取Stream流
        int[] arr = {1,2,3,4,5,6};
        String[] arr2 = {"a","b","c"};
        
        // 3.1获取stream流
        IntStream stream = Arrays.stream(arr);
        Stream<String> stream1 = Arrays.stream(arr2);

// 4.一堆零散数据获取Stream流
        // 注意:方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组,但是数组必须是引用数据类型。如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream中。
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);

2.2 Stream流的中间方法

  • filter:过滤
  • limit:获取前几个元素
  • skip:跳过前几个元素
  • distinct:元素重复,依赖(hashcode和equals方法)
  • concat:合并a和b两个流为一个流
  • map:转换流中的数据类型

注意:
1.中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程。
2.修改Stream流中的数据,不会影响原来集合或者数组中的数据。

public static void main(String[] args) {
        List<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"张无忌","周芷若","赵敏","宋青书","张三丰","独孤求败","张无忌","张无忌");
        List<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"张无忌","周芷若","赵敏");

        // 过滤
        list1.stream().filter(s -> s.startsWith("张")).forEach(s-> System.out.println(s));
        // 获取前几个
        list1.stream().limit(3).forEach(s-> System.out.println(s));
        // 跳过
        list1.stream().skip(4).forEach(s-> System.out.println(s));
		// 去重
		list1.stream().distinct().forEach(s -> System.out.println(s));
		// 合并
		Stream.concat(list1.stream(),list2.stream()).forEach(s -> System.out.println(s));

    }
}

map:转换流中的数据类型

List<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌-15","周芷若-20","赵敏-14","宋青书-19","张三丰-90","独孤求败-101");
        /**
         * map 转换流中的数据类型
         * String->int
         * apply的形参s:依次表示流里面的每一个数据
         * 返回值:表示转换之后的数据
         */
list.stream().map(new Function<String, Integer>() {

            @Override
            public Integer apply(String s) {
                String[] split = s.split("-");
                int age = Integer.parseInt(split[1]);
                return age;
            }
        }).forEach(s-> System.out.println(s));

// lambda表达式书写
list.stream().map(s ->
            Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.println(s));

2.3 Stream流的终结方法

  • forEach:遍历
  • count:统计
  • toArray:收集流中的数据,放到数组中
  • collect:收集流中的数据,放到集合中(List、Set、Map)

我们先创建一个User类,方便我们后续的操作

public class User implements Serializable {
    private String name;
    private Integer age;
    private String sex;

    public User() {
    }

    public User(String name, Integer age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
List<User> userList = new ArrayList<>();
Collections.addAll(userList,new User("张无忌",15,"男"),
        new User("张无忌",15,"男"),
        new User("张三丰",90,"男"),
        new User("赵敏",16,"女"),
        new User("周芷若",20,"女"));

// forEach:遍历
userList.stream().forEach(new Consumer<User>() {
    @Override
    public void accept(User user) {
       System.out.println(user.toString());
    }
});
userList.stream().forEach(user -> System.out.println(user.toString()));
// count:统计
long count = userList.stream().count();

收集流中的数据,放到数组中

/**
 * IntFunction的泛型:具体类型的数组
 * apply的形参:流中数据的个数,要跟数组的长度保持一致
 * apply的返回值:具体类型的数组
 * 方法体:就是创建数组
 */
 User[] userArray = userList.stream().toArray(new IntFunction<User[]>() {
      @Override
      public User[] apply(int value) {
          return new User[value];
      }
 });
 // lambda表达式简化上述代码
 User[] userArray = userList.stream().toArray(value -> new User[value]);
 System.out.println(Arrays.toString(userArray));

toArray方法的参数作用:负责创建一个指定类型的数组。底层:会依次得到流里面的每一个数据,并把数据放到数当中。返回值:是一个装着流里面所有数据的数组

收集流中的数据,放到List集合中

// 获取姓张的用户
List<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","周芷若","赵敏","宋青书","张三丰","独孤求败","张无忌","张无忌");
List<String> stringList = list1.stream().filter(s -> s.startsWith("张")).collect(Collectors.toList());
System.out.println(stringList);

收集流中的数据,放到Set集合中

List<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","周芷若","赵敏","宋青书","张三丰","独孤求败","张无忌","张无忌");
Set<String> stringSet = list1.stream().filter(s -> s.startsWith("张")).collect(Collectors.toSet());

因为Set是不可重复的,所以会自动去重

收集流中的数据,放到Map集合中

List<User> userList = new ArrayList<>();
Collections.addAll(userList,new User("张无忌",15,"男"),
        new User("张三丰",90,"男"),
        new User("赵敏",16,"女"),
        new User("周芷若",20,"女"));
/**
 * toMap:
 * 参数一表示键的生成规则
 * 参数二表示值得生成规则
 *
 * 参数一:Function泛型一:表示流中每一个数据的类型
 *                泛型二:表示Map集合中键的数据类型
 *       方法apply形参:依次表示流中的每一个数据
 *               方法体:生成键的代码
 *               返回值:已经生成的键
 * 参数二:Function泛型一:表示流中每一个数据的类型
 *                泛型二:表示Map集合中值的数据类型
 *       方法apply形参:依次表示流中的每一个数据
 *               方法体:生成值的代码
 *               返回值:已经生成的值
 */
Map<String, Integer> map = userList.stream().filter(user -> "男".equals(user.getSex())).collect(Collectors.toMap(new Function<User, String>() {
    @Override
    public String apply(User user) {
        return user.getName();
    }
}, new Function<User, Integer>() {
    @Override
    public Integer apply(User user) {
        return user.getAge();
    }
 }));
// lambda表达式简化上述代码
Map<String, Integer> map = userList.stream().filter(user -> "男".equals(user.getSex()))
                .collect(Collectors.toMap(user -> user.getName(), user -> user.getAge()));
System.out.println(map);

OK,以上内容就是Stream流的一些主要使用方法,当然还有很多实用的方法,例如Order By排序,Group By分组等。
小伙伴们自行去研究学习一下吧~

原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下

👍 点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!

⭐️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!

✏️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!

评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

IDEA上的操作工

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

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

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

打赏作者

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

抵扣说明:

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

余额充值