前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java8-Stream API 详解

Java8-Stream API 详解

作者头像
用户7886150
修改2020-12-14 15:16:03
4740
修改2020-12-14 15:16:03
举报
文章被收录于专栏:bit哲学院bit哲学院

参考链接: 如何在Java 8中打印Stream的元素

摘要 

 Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream。Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。 

简介 

流(Stream)是数据通道,用于操作数据源(集合,数组等)所生成的元素序列 “集合讲的的是数据,流讲的是计算” 注意:  ① Stream不会存储元素  ② Stream不会改变源对象,相反他们会返回一个持有结果的新的Stream  ③ Stream操作是延迟执行的,这意味着他们等到需要结果的时候才会执行(惰性求值) 

Stream操作的三个步骤 

创建Stream 一个数据源(如:集合,数组)获取一个流中间操作 一个中间操作链,对数据源的数据进行处理终止操作(终端操作) 一个终止操作,执行中间操作链,并产生结果  

一:创建Stream 

Collection提供了两个方法.stream()与paralleStream() 

@org.junit.Test

public void test4(){

    List<Integer> list = new ArrayList<>();

    Stream<Integer> stream = list.stream();//串行流

    Stream<Integer> integerStream = list.parallelStream();//并行流

}

通过Arrays中的Stream()获取一个数组流。 

 Integer[] integers ={};

 Stream<Integer> stream1 = Arrays.stream(integers);

通过Stream类中静态方法of() 

Stream<String> stream2 = Stream.of("aaa", "bbb");

创建无限流(无穷的数据) 

  生成 //通过生成器产生5个10以内的随机数,如果不使用limit就会无限生成10以内随机数

Stream.generate(() -> Math.random() * 10).limit(5).forEach(System.out::println);

----------输出--------

0.8320556195819129

6.260534125204207

7.344094646332503

0.18490598959698068

6.392272744710005

  迭代 //通过迭代的方式(一元运算)生成5个数

Stream.iterate(0,x->x+2).limit(5).forEach(System.out::println);

-------------------输出------------

0

2

4

6

8

二:中间操作 

 多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部执行,称为“惰性求值” 

 List<Integer> list = Arrays.asList(1,2,3,523,21,55);

Stream<Integer> stream3 = list.stream().filter(x -> {

         System.out.println("函数执行");

         return x > 10;

 // stream3.forEach(System.out::println);

 上面的代码没有终止操作,当你运行时不会打印任何东西 

①筛选与切片 

filter----接收Lambda,从流中排除某些元素 

//filter()中需要使用断言型接口(Predicate)

List<Integer> list = Arrays.asList(1,2,3,523,21,55);

Stream<Integer> stream3 = list.stream().filter(x -> x > 10);

stream3.forEach(System.out::println);

limit----截断流,使其元素不超过给定数量 

List<Integer> list = Arrays.asList(1,2,3,523,21,55);

Stream<Integer> stream3 = list.stream().limit(3);

stream3.forEach(System.out::println);

--------------------输出---------------------

1

2

3

skip----跳过元素返回一个抛弃了前n个元素的流,若流中元素不满足n个,则返回一个空流,与limit形成互补 

List<Integer> list = Arrays.asList(1,2,3,523,21,55);

Stream<Integer> stream3 = list.stream().skip(3);

stream3.forEach(System.out::println);

--------------------输出---------------------

523

21

55

distinct----筛选,通过流所所生成元素的hashCode()和equals()去除重复元素 

  List<Integer> list = Arrays.asList(1,2,3,3,2,4);

  Stream<Integer> stream3 = list.stream().distinct();

  stream3.forEach(System.out::println);

  --------------------输出---------------------

  1

  2

  3

  4

注意:自定义的实体类使用distinct去重时,一定要先重写hashCode()和equals() 

②映射 

map----接收Lambda,将元素转换为其他形式或提取信息时,接收一个函数作为参数,该函数被应用到每个元素上,并将其映射成一个新的元素//map()里面使用函数型接口(Function)

List<String> list = Arrays.asList("aa","bb","cc");

Stream<String> stream3 = list.stream().map(String::toUpperCase);

stream3.forEach(System.out::println);

----------------------输出-----------------------

AA

BB

CC

------------------------------------------------

集合里的每一个元素都会使用到String.toUpperCase()方法

它是以aa作为一个元素,bb作为一个元素 

 flatMap----接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接一个流List<String> list = Arrays.asList("aa","bb","cc");

       Stream<String> stream3 = list.stream().flatMap(l -> {

           String[] strings = l.split("");

           return Arrays.stream(strings);

       });

stream3.forEach(System.out::println);

-------------------输出-----------

a

a

b

b

c

c

-----------------------------------------------

flatMap将原来的流转换为一个新的流并且,是以每一个值为单位的

③排序 

sorted() 自然排序 按照Comparable的方式List<String> list = Arrays.asList("aa","cc","bb");

Stream<String> stream3 = list.stream().sorted();

stream3.forEach(System.out::println);

---------------输出-----------

aa

bb

cc

 sorted( Comparator com)定制排序 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

 Stream<Integer> stream3 = list.stream().sorted(Integer::compare);

 stream3.forEach(System.out::println);

 --------------输出--------------

 1

 2

 3

 3

 6

 8

 9

终止操作 

①查找与匹配 

allMatch----检查是否匹配所有元素//allMatch()里面的时断言型接口(Predicate)

 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

 boolean b = list.stream().allMatch(x -> x > 3);

 System.out.println(b);

 ------------------输出--------------------

 false

 //因为不是所有的数都大于3

 anyMatch----检查是否有匹配至少一个元素//anyMatch()里面的时断言型接口(Predicate)

 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

 boolean b = list.stream().anyMatch(x -> x > 3);

 System.out.println(b);

  ------------------输出--------------------

 true

 //只要有大于3的数就返回true

 noneMatch----检查是否没有匹配的元素//noneMatch()里面的时断言型接口(Predicate)

List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

boolean b = list.stream().noneMatch(x -> x > 3);

System.out.println(b);

 ------------------输出--------------------

 false

 //双重否定,返回false就是有匹配的元素

 findFirst----返回第一个元素List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

Optional<Integer> first = list.stream().findFirst();

System.out.println(first.get());

-----------------输出----------------

1

 findAny----返回当前流中的任意一元素List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

Optional<Integer> first = list.stream().findAny();

System.out.println(first.get());

-----------------输出----------------

1

 count-----返回流中元素的总数List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

long count = list.stream().count();

System.out.println(count);

-----------------输出----------------

7

 max----返回流中最大值 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

 Optional<Integer> max = list.stream().max(Integer::compareTo);

 System.out.println(max.get());

 -----------------输出----------------

9

 min----返回流中的最小值List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

Optional<Integer> min = list.stream().min(Integer::compareTo);

System.out.println(min.get());

 -----------------输出----------------

1

 forEach----遍历流中的元素 List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

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

 -----------------输出----------------

1

3

2

6

8

3

9

//注意:forEach的迭代操作是由Stream API完成的称为内部迭代

//借助于iterator的方式为外部迭代

②归约 

reduce(T identity,BinaryOperator)—可以将流中元素反复结合起来得到一个值,返回T List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

 Integer reduce = list.stream().reduce(0, (x, y) -> x + y);

 System.out.println(reduce);

 -----------------输出----------------

 32

 //根据2元运算将所有的数加起来

 //首先以0为x,1为y,结果为1,然后1为x,取3为y,结果为4,以4为x...以此类推

 reduce(BinaryOpreator)----可以将流中元素反复结合起来,返回Optional< T > List<Integer> list = Arrays.asList(1,3,2,6,8,3,9);

 Optional<Integer> reduce = list.stream().reduce((x, y) -> x + y);

 System.out.println(reduce.get());

  -----------------输出----------------

 32

 //原理同上,只是这里没有初始值,直接取1为x

 //所以ist就有可能为空,当返回的值可能为空时,结果存储在Optional容器中,避免空指针异常

③收集 

collect----将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法 

 Colloector 接口中方法的实现决定了如何对流执行手机操作(如收集到List、Set、Map中)但是Collectots实用类提供了很多静态方法,可以方便的创建常见收集器实例 

接下来进行详细介绍 首先创建一个实体类 

public class User {

    private String name;

    private Integer age;

    private double salary;

    public User(String name, Integer age, double salary) {

        this.name = name;

        this.age = age;

        this.salary = salary;

    }

    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 double getSalary() {

        return salary;

    }

    public void setSalary(double salary) {

        this.salary = salary;

    }

    @Override

    public String toString() {

        return "User{" +

                "name='" + name + '\'' +

                ", age=" + age +

                ", salary=" + salary +

                '}';

    }

    @Override

    public boolean equals(Object o) {

        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        return Double.compare(user.salary, salary) == 0 &&

                Objects.equals(name, user.name) &&

                Objects.equals(age, user.age);

    }

    @Override

    public int hashCode() {

        return Objects.hash(name, age, salary);

    }

}

在测试类中准备好数据 

public class StreamTest {

     List<User> user = Arrays.asList(new User("张三",12,1000.00),

                                    new User ("李四",32,4000),

                                    new User ("王五",40,4000),

                                    new User ("王五",40,4000));

}

根据名称生成一个新的List 

 List<String> list = user.stream().map(User::getName).collect(Collectors.toList());

 list.forEach(System.out::println);

 -----------------输出--------------

 张三

 李四

 王五

 王五

根据名称生成一个新的Set 

 Set<String> set = user.stream().map(User::getName).collect(Collectors.toSet());

 set.forEach(System.out::println);

 -----------------输出--------------

 张三

 李四

 王五

根据名称生成一个新的HashSet 

 HashSet<String> hashSet = user.stream().map(User::getName).collect(Collectors.toCollection(HashSet::new));

 hashSet.forEach(System.out::println);

 -----------------输出--------------

 李四

 张三

 王五

获取流中的元素总数 

Long count = user.stream().collect(Collectors.counting());

System.out.println(count);

-----------------输出--------------

4

根据工资获取平均值 

Double avg = user.stream().collect(Collectors.averagingDouble(User::getSalary));

System.out.println(avg);

-----------------输出--------------

3250.0

根据工资获取总和 

Double sum = user.stream().collect(Collectors.summingDouble(User::getSalary));

System.out.println(sum);

-----------------输出--------------

13000.0

根据工资获取组函数 

 DoubleSummaryStatistics sum = user.stream().collect(Collectors.summarizingDouble(User::getSalary));

 System.out.println(sum);

 -----------------输出--------------

 DoubleSummaryStatistics{count=4, sum=13000.000000, min=1000.000000, average=3250.000000, max=4000.000000}

根据工资获取最大值 

 Optional<User> max = user.stream().collect(Collectors.maxBy(Comparator.comparingDouble(User::getSalary)));

 System.out.println(max.get());

 -----------------输出--------------

 User{name='李四', age=32, salary=4000.0}

根据工资获取最小值 

 Optional<User> min = user.stream().collect(Collectors.minBy(Comparator.comparingDouble(User::getSalary)));

 System.out.println(min.get());

 -----------------输出--------------

 User{name='张三', age=12, salary=1000.0}

分组 

Map<Double, List<User>> map = user.stream().collect(Collectors.groupingBy(User::getSalary));

System.out.println(map);

-----------------输出--------------

{4000.0=[User{name='李四', age=32, salary=4000.0}, User{name='王五', age=40, salary=4000.0}, User{name='王五', age=40, salary=4000.0}], 1000.0=[User{name='张三', age=12, salary=1000.0}]}

多级分组 

Map<Double, Map<String, List<User>>> collect = user.stream().collect(Collectors.groupingBy(User::getSalary, Collectors.groupingBy(

                u -> {

                    if ( u.getAge() <= 12) {

                        return "青年";

                    } else if ( u.getAge() <= 32) {

                        return "中年";

                    } else {

                        return "老年";

                    }

                }

        )));

System.out.println(collect);    

-----------------输出--------------    

{4000.0={老年=[User{name='王五', age=40, salary=4000.0}, User{name='王五', age=40, salary=4000.0}], 中年=[User{name='李四', age=32, salary=4000.0}]}, 1000.0={青年=[User{name='张三', age=12, salary=1000.0}]}}

分区 

Map<Boolean, List<User>> collect1 = user.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 3000));

System.out.println(collect1);

-----------------输出--------------   

{false=[User{name='张三', age=12, salary=1000.0}], true=[User{name='李四', age=32, salary=4000.0}, User{name='王五', age=40, salary=4000.0}, User{name='王五', age=40, salary=4000.0}]}

连接 

String s = user.stream().map(User::getName).collect(Collectors.joining("--"));

System.out.println(s);

-----------------输出--------------

张三--李四--王五--王五

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档