收藏夹吃灰系列(十四):Java8 StreamAPI的详细用法 | 开箱即用,超级详细。

Posted bug菌√

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了收藏夹吃灰系列(十四):Java8 StreamAPI的详细用法 | 开箱即用,超级详细。相关的知识,希望对你有一定的参考价值。

目录:

一、概述

二、概念

1、Stream是什么

2、Stream特性

3、Stream创建方式

        i、方式一:

        ii、方式二:

4、流操作分类

5、使用流程

6、stream 区分 parallelStream

7、Stream 中的静态方法

a、of()

b、iterate()

c、concat()

d、generate()

e、empty()

f、builder()

三、实战演练

1、遍历输出(forEach)

 2、归集(toList、toMap)

 3、排序(sorted)

4、去重(distinct)

 四、往期热文推荐


        Hi,我是bug菌,我又来啦。今日前来,不为别事,只想记录一篇自己对它的理解及使用,还请大家笑纳!途中如果有bug菌理解不对的地方,还请立即打断指正,以免误人,哈哈哈哈哈。

 

        先请教大家一个问题,你们对java8 新特性熟悉吗?或者平时项目中,有那些新特性运用到了?可以评论区告诉bug菌,我会接下来的一段日子里根据大家的评论来恶补一些干货。比如:StreamAPI、Lambda 表达式、Date Time API等用法。 

今天,我就要讲讲java8新特性之Stream API,尽量做到句句是重点。

一、概述

        Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

        使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。

        简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

二、概念

1、Stream是什么

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

        Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。

2、Stream特性

  • stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
  • stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
  • stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。

3、Stream创建方式

      Stream可以由数组或集合创建。如下所示:

        i、方式一:

        通过 java.util.Collection.stream() 方法用集合创建流

List<String> strs = Arrays.asList("a", "b", "c");
 // 创建一个顺序流
 Stream<String> stream = strs.stream();

 // 创建一个并行流
 Stream<String> parallelStream = strs.parallelStream();

        ii、方式二:

         通过java.util.Arrays.stream(T[] array)方法用数组创建流

String[] strs = new String[8]; 
Stream<String> stream = Arrays.stream(strs );

4、流操作分类

对流的操作可分为两种:

  • 中间操作,每次返回一个新的流,可以有多个。
  • 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。

5、使用流程

        当使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source) → 数据转换→执行操作获取想要的结果,每次转换原有 Stream 对象不改变, 返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道。

6、stream 区分 parallelStream

        stream是顺序流,由主线程按顺序对流执行操作。

        parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。

7、Stream 中的静态方法

如下我将一一列举及解释其用法,尽可能做到句句是重点。

a、of()

用于为给定元素创建一个顺序流。如下代码示例:

//用于为给定元素创建顺序流
Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5);
stream1.forEach(System.out::print);//1 2 3 4 5

b、iterate()

指定一个常量seed,生成从seed到常量f(由UnaryOperator返回的值得到)的流。如下代码示例:

//根据起始值seed(0),每次生成一个指定递增值(n+1)的数,limit(5)用于截断流的长度,即只获取前5个元素。
 Stream.iterate(10, x -> x + 10).limit(5).forEach(System.out::print);//10 20 30 40 50

c、concat()

合并两个流。如下代码示例:

String[] strs = "a","b","c";
Integer[] ints = 1,2,3;
Stream concat = Stream.concat(Arrays.stream(strs), Arrays.stream(ints));
concat.forEach(System.out::print);//abc123

d、generate()

流generate(Supplier s) 返回无限顺序无序流,其中每个元素由提供的供应商生成。

// 这适用于生成恒定流,随机元素流等。
Stream.generate(new Random()::nextInt).limit(5).forEach(System.out::println);//1149006011  -703426624  774541719 942720678 1437848577

e、empty()

创建一个空顺序流。如下代码示例:

Stream<String> empty = Stream.empty();
empty.forEach(System.out::println);//无输出

f、builder()

构建流。如下代码示例:

Stream.Builder<String> builder = Stream.builder();
builder.add("a");
builder.add("b");
builder.add("c");
builder.add("d");
builder.add("e");
builder.build().forEach(System.out::print); //abcde

三、实战演练

        接下来,大批代码向你袭来!我将用几个真实案例将Stream使得明明白白,你只需要跟着敲一遍,你就能学会。

案例使用的实体类。如下:

/**
 * 用户基本信息实体
 */
@TableName("user")
public class UserEntity implements Serializable 

	private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO) //表示该id为自增,新增时候不需要手动设置id。
    private Integer id;

    @TableField(value = "name")
    private String name;

    @TableField(value = "age")
    private Integer age;

    @TableField(value = "sex")
    private String sex;

    @TableField(value = "address")
    private String address;

    @TableField(value = "describes")
    private String describes;

    public String getDescribes() 
        return describes;
    

    public void setDescribes(String describes) 
        this.describes = describes;
    

    public Integer getId() 
        return id;
    

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

    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;
    

    public String getAddress() 
        return address;
    

    public void setAddress(String address) 
        this.address = address;
    

    @Override
    public String toString() 
        return this.id + " - " + this.name+ " - " +this.getSex();
    

1、遍历输出(forEach)

a、控制台输出每一个用户对象;

List<UserEntity> users = userService.list();
users.stream().forEach(System.out::println);

b、提取符合条件的集合第一个对象。比如提取年龄大于20且性别是男性的第一条数据。

Optional<UserEntity> user = users.stream().filter(p -> p.getAge() > 20 && p.getSex().equals("男")).findFirst();

 或者写多个filter 也是可以的。

Optional<UserEntity> user = users.stream().filter(p -> p.getAge() > 20)
                                          .filter(p -> p.getSex().equals("男"))
                                          .findFirst();

 输出如下:

 2、归集(toList、toMap、toSet)

因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toListtoSettoMap比较常用,另外还有toCollectiontoConcurrentMap等复杂一些的用法。

下面分别用一个案例演示toListtoMaptoSet

i、比如提取List对象中的id归集到一个新集合中。怎么快速优雅?

List<Integer> ids = users.stream().map(UserEntity::getId).collect(Collectors.toList());

 ii、提取对象中的两值转换成map形式;比如:name对应值sex,诸如这样:"张三":"男","李四":"女"。

Map<String, String> collect = users.stream().collect(Collectors.toMap(UserEntity::getName, UserEntity::getSex));

iii、提取符合过滤条件的对象转成set集合。

 Set<UserEntity> set = users.stream().filter(p -> p.getAge() > 20).collect(Collectors.toSet());

 3、排序(sorted)

i、将用户按年龄从小到大排序。

List<Integer>sortList1 = users.stream().sorted(Comparator.comparing(UserEntity::getAge)).map(UserEntity::getAge)
                .collect(Collectors.toList());

ii、将用户按年龄从大到小排序。

List<Integer> sortList2 = users.stream().sorted(Comparator.comparing(UserEntity::getAge).reversed())
                .map(UserEntity::getAge).collect(Collectors.toList());

 

4、去重(distinct)

流也可以进行合并、去重、限制、跳过等操作。

 i、比如去掉重复用户;

List<UserEntity> distinctList = users.stream().distinct().collect(Collectors.toList());

        好啦!两个疑问都替大家解答了,看到这里,不给赞吗?

        好啦!两个疑问都替大家解答了,看到这里,不给赞吗?

        好啦!两个疑问都替大家解答了,看到这里,不给赞吗?


 四、往期热文推荐

❤如果文章对您有所帮助,就请在文章末尾的左下角把大拇指点亮吧!(#^.^#);

❤如果喜欢bug菌分享的文章,就请给bug菌点个关注吧!(๑′ᴗ‵๑)づ╭❤~;

❤对文章有任何问题欢迎小伙伴们下方留言或者入群探讨【群号:708072830】;

❤鉴于个人经验有限,所有观点及技术研点,如有异议,请直接回复参与讨论(请勿发表攻击言论,谢谢);

❤版权声明:本文为博主原创文章,转载请附上原文出处链接和本文声明,版权所有,盗版必究!(*^▽^*).

以上是关于收藏夹吃灰系列(十四):Java8 StreamAPI的详细用法 | 开箱即用,超级详细。的主要内容,如果未能解决你的问题,请参考以下文章

收藏夹吃灰系列(十四):Java8 StreamAPI的详细用法 | 开箱即用,超级详细。

进收藏夹吃灰系列——Java基础快速扫盲

收藏夹吃灰系列:Springboot配置Thymeleaf实现静态页面访问 | 超级详细,建议收藏!

收藏夹吃灰系列:Springboot配置Thymeleaf实现静态页面访问 | 超级详细,建议收藏!

首次公开,整理12年积累的博客收藏夹,零距离展示《收藏夹吃灰》系列博客

收藏夹吃灰系列:谁说Spring提供的@Scheduled定时不好用?师妹看了直呼叫好!