四、streamAPI

本文深入探讨了Java8的Stream API,包括流的基本概念、创建流、中间操作(筛选与切片、映射、排序)以及终止操作(查找与匹配、归纳与搜集)。此外,还介绍了并行流与顺序流的区别和使用,通过实例展示了如何利用Stream API处理数据,优化代码。最后,通过一系列练习题进一步巩固了Stream API的运用。
摘要由CSDN通过智能技术生成

目录

第一节:java8 Stream基本概念

一、java8Stream概述

1、stream定义

2、图解stream

3、stream流到底是什么?

4、stream注意事项

第二节:StreamApi之创建流

一、Stream创建方式

1、通过collection系列集合获取stream

2、通过Arrays获取stream

3、通过Stream类获取stream

4、无限流

二、实例演示创建Stream

1、代码实现

2、运行效果

第三节:StreamApi之筛选与切片

一、stream的中间操作概述

二、stream的中间操作之筛选和切片

1、filter(Predicate p)方法

2、distinct()方法

3、limit(long maxSize)方法

4、skip(long n)方法

三、实例演示stream的中间操作之筛选和切片

1、实例演示filter(Predicate p)方法

2、实例演示limit(long maxSize)方法

3、实例演示distinct()方法

4、实例演示skip(long n)方法

第四节:StreamApi之映射

一、stream的映射概述

1、map映射

2、flatMap映射

二、实例演示stream的映射操作

1、演示map映射

2、演示flatMap映射

第五节:StreamApi之排序

一、stream的排序概述

二、演示stream的排序操作

1、演示自然排序

2、演示定制排序

第六节:StreamApi之终止操作

一、stream的终止操作

二、查找与匹配

1、allMatch方法

2、anyMatch方法

3、noneMatch方法

4、findFirst方法

5、findAny方法

6、count方法

7、max方法

8、min方法

三、实例演示

1、修改数据源

2、代码实现

3、运行效果

第七节:StreamApi之归纳与搜集

一、归约

1、reduce(T identity,BinaryOperator)和reduce(BinaryOperator)方法

2、实例演示

二、搜集

1、collect方法

2、collect方法实例演示

第八节:StreamApi之小小练习题

一、练习1

1、需求

2、代码实现

3、运行效果

二、练习2

1、需求

2、实现

3、运行效果

三、练习3(综合题)

1、找出2011年发生的所有交易,并按交易额排序(从低到高)

2、交易员都在哪些不同的城市工作过

3、查找所有来自剑桥的交易员,并按姓名排序

4、返回所有交易员的姓名字符串,按字符顺序排序

5、有没有交易员是在米兰工作的

6、打印生活在剑桥的交易员的所有交易额

7、所有交易中,最高的交易额是多少

8、找到交易额最小的交易

第九节:并行流与顺序流

一、并行流

1、并行流概念

2、fork/join框架(原始的手段)

3、fork/join框架示例演示

4、java8并行流示例演示


第一节:java8 Stream基本概念

Java 8中有两个最为重要的改变,一个是lambad表达式;另外一个则是StreamAPI(java.util.stream.*);那么接下来我们就来了解一下这个streamAPI的内容!

 

一、java8Stream概述

1、stream定义

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

使用StreanAPI对集合数据进行操作,就类似于使用sql执行的数据库查询。也可以使用streamAPI来合并行执行操作。简而言之,streamAPI提供了一种高效且易于使用的处理数据的方式。

2、图解stream

 

 

如上图所示,java8中的stream操作的流程,首先需要创建一个流,这个流的数据源可以是集合,也可以是数组。然后这个流可以经过一系列的流水线式的的操作,最终生成一个新的流!而对于数据源则没有任何影响!

3、stream流到底是什么?

结合前面的讲解,我们来总结一下stream到底是什么呢?

Stream就是数据管道,用于操作数据源(集合、数组等)所生成的元素序列。

集合的重点在于数据的存储,而流的重点在于计算!

4、stream注意事项

1)、stream自己不会存储元素;

2)、stream不会改变源数据对象,相反的,他会生成并返回一个持有结果的新的stream;

3)、stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行;

5、stream的操作步骤

如上图所示,stream的操作步骤大致上可以分为如下几个步骤:

1)、创建stream

通过一个数据源,如集合、数组,来获取一个流实例;

2)、中间操作

一个中间操作链,对数据源的数据进行处理;

3)、终止操作(终端操作)

一个终止操作出现后,会执行中间操作链,并产生结果;

 

第二节:StreamApi之创建流

一、Stream创建方式

Stream的创建方式一共有四种,分别是:

1、通过collection系列集合获取stream

通过collection系列集合提供的stream()方法获取串行流,或者通过parallelStream()方法获取并行流;

2、通过Arrays获取stream

通过Arrays中的静态方法stream获取一个数组流;

3、通过Stream类获取stream

通过Stream类中的静态方法of()获取一个流;

4、无限流

无限流又分为迭代和生成两种方式创建;

 

二、实例演示创建Stream

1、代码实现

我们在这里就一起演示这四种创建方式:

我们在这里就一起演示这四种创建方式:

package streamAPI;

 

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

 

import 为什么要使用lambad表达式.entity.Employee;

 

/**

 * 一、stream的三个操作步骤

 * 1.创建stream

 * 2.中间操作

 * 3.终止操作(终端操作)

 *

 *

 */

public class TestStreamAPI1 {

 

    

     /**

      * 创建流

      * 我们创建stream流有四种方式

      * 如下:

      */

     public static void testCreateStream() {

        

        

         //1.通过collection系列集合提供的stream()方法获取串行流,或者通过parallelStream()方法获取并行流

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

         Stream<String> stream1 = list.stream();

        

         //2.通过Arrays中的静态方法stream获取一个数组流

         Employee[] emps = new Employee[10];

         Stream<Employee> stream2 = Arrays.stream(emps);

        

         //3.通过Stream类中的静态方法of()获取一个流

         Stream<String> stream3 = Stream.of("aa","bb","cc","dd","ee");

        

         //4.创建无限流

         //1).迭代

         Stream<Integer> stream4 = Stream.iterate(0,(x)->x+2);

         stream4.limit(5).forEach(System.out::println);

        

         //2).生成

         Stream<Double> stream5 = Stream.generate(()->Math.random());

         stream5.limit(5).forEach(System.out::println);

        

     }

    

     public static void main(String[] args) {

         testCreateStream();

     }   

}

2、运行效果

0

2

4

6

8

0.04711765843563487

0.8986789912903362

0.31479564241549685

0.14205863575868716

0.8298402400671744

其实这个运行效果你可以不看的,因为这里主要演示的还是创建流的操作;

 

第三节:StreamApi之筛选与切片

那么我们前面已经将stream的创建方式介绍过了,接下来我们看一下stream的中间操作;

一、stream的中间操作概述

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

在stream中的中间操作使用到了内部迭代,这个迭代是由streamAPI帮我们做的;

与内部迭代相对应的就是外部迭代了,其实说白了就是我们自己写的迭代代码,就是外部迭代!

其具体的操作可以分为很多种,比如筛选和切片、映射、排序等等!

在这一节课我们先来了解一下筛选和切片!

 

二、stream的中间操作之筛选和切片

筛选和切片常用的方法如下:

1、filter(Predicate p)方法

该方法用于接收lambad,从流中排除某些元素;

2、distinct()方法

该方法用于筛选,通过流所产生的元素的hashCode()和equals()去除重复元素;

3、limit(long maxSize)方法

该方法用于截断流,使其元素不超过给定数量;

4、skip(long n)方法

该方法用于跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补;

 

三、实例演示stream的中间操作之筛选和切片

1、实例演示filter(Predicate p)方法

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

 

import 为什么要使用lambad表达式.entity.Employee;

 

public class TestStreamAPI2 {

 

     //创建数据

     private static List<Employee> employees = Arrays.asList(

         new Employee("张三",18,9999.99),

         new Employee("李四",38,5555.55),

         new Employee("王五",50,6666.66),

         new Employee("赵六",16,3333.33),

         new Employee("田七", 8,7777.77)

     );

    

     public static void testFilter() {

        

         //获取员工年龄大于等于35岁的员工信息

         Stream<Employee> stream1 = employees.stream().filter((e)->e.getAge()>=35);

         //为了能看到效果,我们暂时先给他一个终止操作,后期会详细讲解终止操作

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

     }

 

     public static void main(String[] args) {

         testFilter();

     }   

}

2)、运行效果

Employee [name=李四, age=38, salary=5555.55]

Employee [name=王五, age=50, salary=6666.66]

2、实例演示limit(long maxSize)方法

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

 

import 为什么要使用lambad表达式.entity.Employee;

 

public class TestStreamAPI2 {

 

     public static void testLimit() {

         //获取集合中员工工资大于5000的前两个员工信息

         employees.stream().

                    filter((e)->e.getSalary()>5000).

                    limit(2).

                    forEach(System.out::println);

     }

     public static void main(String[] args) {

         testLimit();

     }   

}

2)、运行效果

Employee [name=张三, age=18, salary=9999.99]

Employee [name=李四, age=38, salary=5555.55]

3)、备注

Limit方法支持短路操作,一旦获取到满足条件的数据后,后面没有迭代的流,便不会再进行迭代了!这样的话,在某种场景下是可以提高效率的!和我们短路与&&和短路或||是一样的;

3、实例演示distinct()方法

1)、代码实现

package streamAPI;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

import 为什么要使用lambad表达式.entity.Employee;

public class TestStreamAPI2 {

     public static void testDistinct() {

         employees.stream().

              distinct().

              forEach(System.out::println);

     }

 

     public static void main(String[] args) {

         testDistinct();

     }   

}

2)、运行效果

Employee [name=张三, age=18, salary=9999.99]

Employee [name=李四, age=38, salary=5555.55]

Employee [name=王五, age=50, salary=6666.66]

Employee [name=赵六, age=16, salary=3333.33]

Employee [name=田七, age=8, salary=7777.77]

3)、备注

使用去重方法的时候,必须重新需要去重元素中的hashCode和equals函数;

4、实例演示skip(long n)方法

1)、代码实现

package streamAPI;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

import 为什么要使用lambad表达式.entity.Employee;

public class TestStreamAPI2 {

      public static void testSkip() {

           //获取集合中员工工资大于5000的后两个员工信息

           employees.stream().

                 filter((e)->e.getSalary()>5000).

                 skip(2).

                 forEach(System.out::println);

      }

      public static void main(String[] args) {

           testSkip();

      }

}

2)、运行效果

Employee [name=王五, age=50, salary=6666.66]

Employee [name=田七, age=8, salary=7777.77]

 

第四节:StreamApi之映射

一、stream的映射概述

映射操作分为map和flatMap两种:

1、map映射

接受到lambad后,将元素转换成其他形式或提取信息,接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素;

2、flatMap映射

接受一个函数作为参数,并将流中的每个值都换成另外一个流,然后把左右流合并成一个新的流;

 

二、实例演示stream的映射操作

1、演示map映射

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

 

import 为什么要使用lambad表达式.entity.Employee;

 

public class TestStreamAPI3 {

    

     //创建数据

     private static List<Employee> employees = Arrays.asList(

         new Employee("张三",18,9999.99),

         new Employee("李四",38,5555.55),

         new Employee("王五",50,6666.66),

         new Employee("赵六",16,3333.33),

         new Employee("田七", 8,7777.77),

         new Employee("田七", 8,7777.77)

     );

    

    

     public static void testMap() {

         System.out.println("需求1:将给定集合中的数据专为大写");

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

         list.stream().map((str)->str.toUpperCase()).forEach(System.out::println);

        

         System.out.println("需求2:提取员工姓名");

         employees.stream().map(Employee::getName).forEach(System.out::println);

     }

    

     public static void main(String[] args) {

         testMap();

     }

    

}

2)、运行效果

需求1:将给定集合中的数据专为大写

AA

BB

CC

DD

EE

需求2:提取员工姓名

张三

李四

王五

赵六

田七

田七

2、演示flatMap映射

首先,我们来看一下为什么要有flatMap这个操作;

我们先给定一个需求:将指定集合中的字符串拆分为字符,并打印输出之;

下面我们来看一下使用map操作的实现方式:

1)、代码实现

package streamAPI;

 

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

 

import 为什么要使用lambad表达式.entity.Employee;

 

public class TestStreamAPI3 {

    

     //创建数据

     private static List<Employee> employees = Arrays.asList(

         new Employee("张三",18,9999.99),

         new Employee("李四",38,5555.55),

         new Employee("王五",50,6666.66),

         new Employee("赵六",16,3333.33),

         new Employee("田七", 8,7777.77),

         new Employee("田七", 8,7777.77)

     );

    

     public static void testMap2() {

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

         Stream<Stream<Character>> stream = list.stream().map(TestStreamAPI3::filterCharacter);

         stream.forEach(sm->{

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

         });

     }

    

     /**

      * 为了演示flatMap,

      * 我们创建一个提取字符串中字符的操作,

      * 最终使其返回一个stream

      * @param str

      * @return

      */

     public static Stream<Character> filterCharacter(String str){

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

         for(Character ch:str.toCharArray()) {

              list.add(ch);

         }

         return list.stream();

     }

    

     public static void main(String[] args) {

         testMap2();

     }

}

2)、运行效果

a

a

b

b

c

c

d

d

e

e

3)、问题

可以看出来这个效果是没有问题的,但是在遍历的时候,是不是要遍历两次啊,这是不是很不符合我们代码的简洁约束啊,所以这个时候就需要使用flatMap操作来对其进行优化了;

下面我们来使用flatMap来演示:

1)、代码实现

package streamAPI;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

import 为什么要使用lambad表达式.entity.Employee;

public class TestStreamAPI3 {

    

     public static void testFlatMap() {

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

         Stream<Character> flatMapStream = list.stream().flatMap(TestStreamAPI3::filterCharacter);

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

     }

    

     /**

      * 为了演示flatMap,

      * 我们创建一个提取字符串中字符的操作,

      * 最终使其返回一个stream

      * @param str

      * @return

      */

     public static Stream<Character> filterCharacter(String str){

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

         for(Character ch:str.toCharArray()) {

              list.add(ch);

         }

         return list.stream();

     }

    

     public static void main(String[] args) {

         testFlatMap();

     }

}

2)、运行效果

a

a

b

b

c

c

d

d

e

e

 

第五节:StreamApi之排序

一、stream的排序概述

排序操作分为sorted自然排序和sortes(Compartor com)定制排序两种:

 

二、演示stream的排序操作

1、演示自然排序

1)、代码实现

package streamAPI;

 

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

 

import 为什么要使用lambad表达式.entity.Employee;

 

public class TestStreamAPI4 {

 

     public static void testSorted() {

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

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

     }

 

     public static void main(String[] args) {

         testSorted();

     }

}

2)、运行效果

aa

bb

cc

dd

ee

2、演示定制排序

1)、代码实现

package streamAPI;

 

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Stream;

 

import 为什么要使用lambad表达式.entity.Employee;

 

public class TestStreamAPI4 {

    

     //创建数据

     private static List<Employee> employees = Arrays.asList(

         new Employee("张三",18,9999.99),

         new Employee("李四",38,5555.55),

         new Employee("王五",50,6666.66),

         new Employee("赵六",16,3333.33),

         new Employee("田七", 8,7777.77),

         new Employee("田七", 8,7777.77)

     );

    

     /**

      * 定制排序:按照姓名排序

      */

     public static void testSortes() {

         employees.stream().sorted((e1,e2)->-e1.getName().compareTo(e2.getName())).forEach(System.out::println);

     }

    

     public static void main(String[] args) {

         testSortes();

     }

}

2)、运行效果

Employee [name=赵六, age=16, salary=3333.33]

Employee [name=田七, age=8, salary=7777.77]

Employee [name=田七, age=8, salary=7777.77]

Employee [name=王五, age=50, salary=6666.66]

Employee [name=李四, age=38, salary=5555.55]

Employee [name=张三, age=18, salary=9999.99]

 

第六节:StreamApi之终止操作

一、stream的终止操作

终止操作,又称为终端操作,终端操作会从流的流水线生成结构,其结构可以是任何不是流的值,例如list、Integer,甚至是void;

我们常见的终端操作有查找、匹配等等,下面我们来看这些常用的方法函数:

二、查找与匹配

1、allMatch方法

该方法用于检测是否匹配所有元素;

2、anyMatch方法

该方法用于检测是否至少匹配一个元素;

3、noneMatch方法

该方法用于是否没有匹配所有元素;

4、findFirst方法

该方法用于返回的第一个元素;

5、findAny方法

该方法用于返回当前流中任意元素;

6、count方法

该方法用于返回流中元素的总个数;

7、max方法

该方法用于返回流中最大值;

8、min方法

该方法用于返回流中最小值;

 

三、实例演示

1、修改数据源

首先,为了演示,我们将这个数据源集合中的实体类再改造的稍微复杂一点点;

package 为什么要使用lambad表达式.entity;

 

public class Employee {

 

    private String name;

   

    private int age;

   

    private double salary;

   

    private Status status;

 

    public Employee(String name, int age, double salary) {

        super();

        this.name = name;

        this.age = age;

        this.salary = salary;

    }

   

    public Employee(String name, int age, double salary,Status status) {

        super();

        this.name = name;

        this.age = age;

        this.salary = salary;

        this.status = status;

    }

 

    public Employee() {

       

    }

   

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public int getAge() {

        return age;

    }

 

    public void setAge(int age) {

        this.age = age;

    }

 

    public double getSalary() {

        return salary;

    }

 

    public void setSalary(double salary) {

        this.salary = salary;

    }

 

    public Status getStatus() {

        return status;

    }

 

    public void setStatus(Status status) {

        this.status = status;

    }

 

    @Override

    public String toString() {

        return "Employee [name=" + name + ", age=" + age + ", salary=" + salary + ", status=" + status + "]";

    }

 

    @Override

    public int hashCode() {

        final int prime = 31;

        int result = 1;

        result = prime * result + age;

        result = prime * result + ((name == null) ? 0 : name.hashCode());

        long temp;

        temp = Double.doubleToLongBits(salary);

        result = prime * result + (int) (temp ^ (temp >>> 32));

        result = prime * result + ((status == null) ? 0 : status.hashCode());

        return result;

    }

 

    @Override

    public boolean equals(Object obj) {

        if (this == obj)

            return true;

        if (obj == null)

            return false;

        if (getClass() != obj.getClass())

            return false;

        Employee other = (Employee) obj;

        if (age != other.age)

            return false;

        if (name == null) {

            if (other.name != null)

                return false;

        } else if (!name.equals(other.name))

            return false;

        if (Double.doubleToLongBits(salary) != Double.doubleToLongBits(other.salary))

            return false;

        if (status != other.status)

            return false;

        return true;

    }

 

    public enum Status{

        FREE,//空闲

        BUSY,//繁忙

        VOCATION;//休假中

    }

   

}

2、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

 

import 为什么要使用lambad表达式.entity.Employee;

import 为什么要使用lambad表达式.entity.Employee.Status;

 

public class TestStreamAPI5 {

   

    //创建数据

    private static List<Employee> employees = Arrays.asList(

        new Employee("张三",18,9999.99,Status.FREE),

        new Employee("李四",38,5555.55,Status.BUSY),

        new Employee("王五",50,6666.66,Status.VOCATION),

        new Employee("赵六",16,3333.33,Status.FREE),

        new Employee("田七", 8,7777.77,Status.BUSY)

    );

   

    public static void testAllMatch() {

        //查看流中的元素的status字段值是否都是BUSY

        boolean b1 = employees.stream().allMatch((e)->e.getStatus().equals(Status.BUSY));

        System.out.println("查看流中的元素的status字段值是否都是BUSY:"+b1);

       

        //查看流中的元素的status字段值是否至少有一个是BUSY

        boolean b2 = employees.stream().anyMatch((e)->e.getStatus().equals(Status.BUSY));

        System.out.println("查看流中的元素的status字段值是否至少有一个是BUSY:"+b2);

       

        //查看流中的元素的status字段值是否全部都不是BUSY

        boolean b3 = employees.stream().noneMatch((e)->e.getStatus().equals(Status.BUSY));

        System.out.println("查看流中的元素的status字段值是否全部都不是BUSY:"+b3);

       

        //按工资排序,然后获取第一个元素

        Optional<Employee> op1 = employees.stream().

                                            sorted((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary())).

                                            findFirst();

        System.out.println("按工资排序,然后获取第一个元素:"+op1.get());

       

        //返回当前流中任意元素:需求,随便给我找个闲人

        Optional<Employee> op2 = employees.stream().filter((e)->e.getStatus().equals(Status.FREE)).findAny();

        System.out.println("返回当前流中任意元素:"+op2.get());

       

       

        //获取总数

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

        System.out.println("获取总数:"+count);

       

        //获取最大值

        Optional<Employee> max = employees.stream().max((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary()));

        System.out.println("工资最高的员工信息:"+max.get());

       

        //获取最小值

        Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compare);

        System.out.println("工资最低的员工信息:"+min.get());

       

    }

   

    public static void main(String[] args) {

        testAllMatch();

    }

}

3、运行效果

查看流中的元素的status字段值是否都是BUSY:false

查看流中的元素的status字段值是否至少有一个是BUSY:true

查看流中的元素的status字段值是否全部都不是BUSY:false

按工资排序,然后获取第一个元素:Employee [name=赵六, age=16, salary=3333.33, status=FREE]

返回当前流中任意元素:Employee [name=张三, age=18, salary=9999.99, status=FREE]

获取总数:5

工资最高的员工信息:Employee [name=张三, age=18, salary=9999.99, status=FREE]

工资最低的员工信息:3333.33

 

第七节:StreamApi之归纳与搜集

接下来我们再看两种终止操作,分别是归纳与搜集;

一、归约

1、reduce(T identity,BinaryOperator)和reduce(BinaryOperator)方法

上述两个方法用于将流中元素反复结合起来,得到一个值;

reduce结合map使用,被称之为map-reduce模式,因为goole用它进行网络所搜而出名;

2、实例演示

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

 

import 为什么要使用lambad表达式.entity.Employee;

import 为什么要使用lambad表达式.entity.Employee.Status;

 

public class TestStreamAPI6 {

   

    //创建数据

    private static List<Employee> employees = Arrays.asList(

        new Employee("张三",18,9999.99,Status.FREE),

        new Employee("李四",38,5555.55,Status.BUSY),

        new Employee("王五",50,6666.66,Status.VOCATION),

        new Employee("赵六",16,3333.33,Status.FREE),

        new Employee("田七", 8,7777.77,Status.BUSY)

    );

   

    public static void test1() {

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

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

        System.out.println(sum);

    }

   

    public static void test2() {

        Optional<Double> resOp = employees.stream().map(Employee::getSalary).reduce(Double::sum);

        System.out.println("工资总数为:"+resOp.get());

    }

   

    public static void main(String[] args) {

        test1();

        test2();

    }

}

2)、运行效果

55

工资总数为:33333.3

 

二、搜集

1、collect方法

该方法用于将流转换为其他形式,接受一个collector接口的实现,用于给stream中元素做汇总的方法;

该方法需要一个参数,这个参数就是一个搜集器,即Collector接口中方法的实现决定了如何对流执行搜集操作,如搜集到list、set、map等等;但是collectors实现类提供了很多静态方法,可以方便的创建常见的搜集器实例,具体方法的实例演示如下:

2、collect方法实例演示

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.HashSet;

import java.util.List;

import java.util.Map;

import java.util.Optional;

import java.util.Set;

import java.util.stream.Collectors;

 

import javax.swing.plaf.synth.SynthSpinnerUI;

 

import 为什么要使用lambad表达式.entity.Employee;

import 为什么要使用lambad表达式.entity.Employee.Status;

 

public class TestStreamAPI6 {

    

     //创建数据

     private static List<Employee> employees = Arrays.asList(

         new Employee("张三",18,9999.99,Status.FREE),

         new Employee("李四",38,5555.55,Status.BUSY),

         new Employee("王五",50,6666.66,Status.VOCATION),

         new Employee("赵六",16,3333.33,Status.FREE),

         new Employee("田七", 8,7777.77,Status.BUSY)

     );

    

     public static void test1() {

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

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

         System.out.println(sum);

     }

    

    

     public static void test2() {

         Optional<Double> resOp = employees.stream().map(Employee::getSalary).reduce(Double::sum);

         System.out.println("工资总数为:"+resOp.get());

     }

    

     public static void test3() {

        

         //放到list集合中

         List<String> names1 = employees.stream().

                                      map(Employee::getName).

                                      collect(/**搜集器**/Collectors.toList());

         System.out.println("list集合中:");

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

        

         //放到set集合中

         Set<String> names2 = employees.stream().

                   map(Employee::getName).

                   collect(Collectors.toSet());

         System.out.println("set集合中:");

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

        

         //放到hashSet中

         HashSet<String> names3 = employees.stream().

                   map(Employee::getName).

                   collect(Collectors.toCollection(HashSet::new));

         System.out.println("HashSet集合中:");

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

        

         //获取平均值

         Double double1 = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));

         System.out.println("平均工资:"+double1);

        

         //获取总和

         Double double2 = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));

         System.out.println("工资总和:"+double2);

        

         //获取最大值

         Optional<Employee> op = employees.stream().collect(Collectors.maxBy((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary())));

         System.out.println("工资最高的人:"+op.get());

        

         //获取最少的工资数

         Optional<Double> double3 = employees.stream().map(Employee::getSalary).collect(Collectors.minBy(Double::compare));

         System.out.println("获取最少的工资数:"+double3);

        

         //按状态分组

         Map<Status, List<Employee>> collectMap = employees.stream().collect(Collectors.groupingBy(Employee::getStatus));

         System.out.println(collectMap);

        

         //多级分组

         Map<Status, Map<String, List<Employee>>> resMap = employees.stream().collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((e)->{

               if(((Employee)e).getAge()<=35) {

                    return "青年";

               }else if(((Employee)e).getAge()<=50) {

                    return "中年";

               }else {

                    return "老年";

               }

          })));

         System.out.println(resMap);

        

         //分区

         Map<Boolean, List<Employee>> resmap2 = employees.stream().collect(Collectors.partitioningBy((e)->e.getSalary()>8000));

         System.out.println(resmap2);

        

     }

     public static void main(String[] args) {

//        test1();

//        test2();

         test3();

     }

}

2)、运行效果

list集合中:

张三

李四

王五

赵六

田七

set集合中:

李四

张三

王五

赵六

田七

HashSet集合中:

李四

张三

王五

赵六

田七

平均工资:6666.660000000001

工资总和:33333.3

工资最高的人:Employee [name=张三, age=18, salary=9999.99, status=FREE]

获取最少的工资数:Optional[3333.33]

{BUSY=[Employee [name=李四, age=38, salary=5555.55, status=BUSY], Employee [name=田七, age=8, salary=7777.77, status=BUSY]], VOCATION=[Employee [name=王五, age=50, salary=6666.66, status=VOCATION]], FREE=[Employee [name=张三, age=18, salary=9999.99, status=FREE], Employee [name=赵六, age=16, salary=3333.33, status=FREE]]}

{BUSY={青年=[Employee [name=田七, age=8, salary=7777.77, status=BUSY]], 中年=[Employee [name=李四, age=38, salary=5555.55, status=BUSY]]}, VOCATION={中年=[Employee [name=王五, age=50, salary=6666.66, status=VOCATION]]}, FREE={青年=[Employee [name=张三, age=18, salary=9999.99, status=FREE], Employee [name=赵六, age=16, salary=3333.33, status=FREE]]}}

{false=[Employee [name=李四, age=38, salary=5555.55, status=BUSY], Employee [name=王五, age=50, salary=6666.66, status=VOCATION], Employee [name=赵六, age=16, salary=3333.33, status=FREE], Employee [name=田七, age=8, salary=7777.77, status=BUSY]], true=[Employee [name=张三, age=18, salary=9999.99, status=FREE]]}

3)、其他

截图部分了解一下即可,没必要全看,API可以百度搜,我们主要是要掌握这个东西都能干嘛!

 

第八节:StreamApi之小小练习题

一、练习1

1、需求

给定一个数字列表[1,2,3,4,5...],返回一个由每个数的平方构成的列表[1,4,9,16,25...]

2、代码实现

package streamAPI;

 

import java.util.Arrays;

 

public class TestStreamAPI7 {

   

    public static void test1() {

        Integer[] nums = new Integer[] {1,2,3,4,5};

        Arrays.stream(nums).map((i)->{

            return i*i;

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

    }

   

    public static void main(String[] args) {

        test1();

    }

}

3、运行效果

1

4

9

16

25

 

二、练习2

1、需求

怎样用map和reduce方法数一数流中有多少个对象;

2、实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

import 为什么要使用lambad表达式.entity.Employee;

 

public class TestStreamAPI7 {

     //创建数据

     private static List<Employee> employees = Arrays.asList(

         new Employee("张三",18,9999.99),

         new Employee("李四",38,5555.55),

         new Employee("王五",50,6666.66),

         new Employee("赵六",16,3333.33),

         new Employee("田七", 8,7777.77),

         new Employee("田七", 8,7777.77)

     );

    

     public static void test2() {

         Optional<Integer> reduce = employees.stream().map((e)->1).reduce(Integer::sum);

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

     }   

     public static void main(String[] args) {

         test2();

     }

}

3、运行效果

6

 

三、练习3(综合题)

1、找出2011年发生的所有交易,并按交易额排序(从低到高)

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

import streamAPI.entity.Trader;

import streamAPI.entity.Transaction;

 

public class TestStreamAPI8 {

   

    private static Trader raoul = new Trader("Raoul","Cambridge");

    private static Trader mario = new Trader("Mario","Milan");

    private static Trader alan = new Trader("Alan","Cambridge");

    private static Trader brian = new Trader("Brian","Cambridge");

   

    private static List<Transaction> transactions = Arrays.asList(

            new Transaction(brian,2011,300),

            new Transaction(raoul,2012,1000),

            new Transaction(raoul,2011,400),

            new Transaction(mario,2012,710),

            new Transaction(mario,2012,700),

            new Transaction(alan,2012,950)

        ); 

   

    /**

     * 找出2011年发生的所有交易,并按交易额排序(从低到高)

     */

    public static void test1() {

        transactions.stream().

            filter((e)->e.getYear()==2011).

            sorted((e1,e2)->Integer.

            compare(e1.getValue(),e2.getValue())).

            forEach(System.out::println);

    }

   

   

    public static void main(String[] args) {

        test1();

    }

}

2)、运行效果

Transaction [trader=Trader [name=Brian, city=Cambridge], year=2011, value=300]

Transaction [trader=Trader [name=Raoul, city=Cambridge], year=2011, value=400]

2、交易员都在哪些不同的城市工作过

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

 

import streamAPI.entity.Trader;

import streamAPI.entity.Transaction;

 

public class TestStreamAPI8 {

   

    private static Trader raoul = new Trader("Raoul","Cambridge");

    private static Trader mario = new Trader("Mario","Milan");

    private static Trader alan = new Trader("Alan","Cambridge");

    private static Trader brian = new Trader("Brian","Cambridge");

   

    private static List<Transaction> transactions = Arrays.asList(

            new Transaction(brian,2011,300),

            new Transaction(raoul,2012,1000),

            new Transaction(raoul,2011,400),

            new Transaction(mario,2012,710),

            new Transaction(mario,2012,700),

            new Transaction(alan,2012,950)

    );

 

    /**

     * 找出2011年发生的所有交易,并按交易额排序(从低到高)

     */

    public static void test2() {

        transactions.stream().

            map((t)->t.getTrader().getCity()).

            distinct().

            forEach(System.out::println);

    }

   

    public static void main(String[] args) {

        test2();

    }

}

2)、运行效果

Cambridge

Milan

3、查找所有来自剑桥的交易员,并按姓名排序

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

 

import streamAPI.entity.Trader;

import streamAPI.entity.Transaction;

 

public class TestStreamAPI8 {

    

     private static Trader raoul = new Trader("Raoul","Cambridge");

     private static Trader mario = new Trader("Mario","Milan");

     private static Trader alan = new Trader("Alan","Cambridge");

     private static Trader brian = new Trader("Brian","Cambridge");

    

     private static List<Transaction> transactions = Arrays.asList(

              new Transaction(brian,2011,300),

              new Transaction(raoul,2012,1000), 

              new Transaction(raoul,2011,400),

              new Transaction(mario,2012,710),

              new Transaction(mario,2012,700),

              new Transaction(alan,2012,950)

     );

    

     /**

      * 查找所有来自剑桥的交易员,并按姓名排序

      */

     public static void test3() {

         transactions.stream().

              filter((t)->t.getTrader().

              getCity().

              equals("Cambridge")).

              map((t)->t.getTrader()).

              sorted((t1,t2)->t1.getName().

              compareTo(t2.getName())).

              distinct().

              forEach(System.out::println);

     }

     public static void main(String[] args) {

         test3();

     }

}

2)、运行效果

Trader [name=Alan, city=Cambridge]

Trader [name=Brian, city=Cambridge]

Trader [name=Raoul, city=Cambridge]

4、返回所有交易员的姓名字符串,按字符顺序排序

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

 

import streamAPI.entity.Trader;

import streamAPI.entity.Transaction;

 

public class TestStreamAPI8 {

   

    private static Trader raoul = new Trader("Raoul","Cambridge");

    private static Trader mario = new Trader("Mario","Milan");

    private static Trader alan = new Trader("Alan","Cambridge");

    private static Trader brian = new Trader("Brian","Cambridge");

   

    private static List<Transaction> transactions = Arrays.asList(

            new Transaction(brian,2011,300),

            new Transaction(raoul,2012,1000),

            new Transaction(raoul,2011,400),

            new Transaction(mario,2012,710),

            new Transaction(mario,2012,700),

            new Transaction(alan,2012,950)

    );

   

   

    /**

     * 返回所有交易员的姓名字符串,按字符顺序排序

     */

    public static void test4() {

        transactions.stream().

            map((t)->t.getTrader().getName()).

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

    }

   

    public static void main(String[] args) {

        test4();

    }

}

2)、运行效果

Alan

Brian

Mario

Mario

Raoul

Raoul

 

5、有没有交易员是在米兰工作的

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

 

import streamAPI.entity.Trader;

import streamAPI.entity.Transaction;

 

public class TestStreamAPI8 {

   

    private static Trader raoul = new Trader("Raoul","Cambridge");

    private static Trader mario = new Trader("Mario","Milan");

    private static Trader alan = new Trader("Alan","Cambridge");

    private static Trader brian = new Trader("Brian","Cambridge");

   

    private static List<Transaction> transactions = Arrays.asList(

            new Transaction(brian,2011,300),

            new Transaction(raoul,2012,1000),

            new Transaction(raoul,2011,400),

            new Transaction(mario,2012,710),

            new Transaction(mario,2012,700),

            new Transaction(alan,2012,950)

    );

   

    /**

     * 有没有交易员是在米兰工作的

     */

    public static void test5() {

        boolean bool = transactions.stream().anyMatch((t)->t.getTrader().getCity().equals("Milan"));

        System.out.println(bool);

           

    }

   

    public static void main(String[] args) {

        test5();

    }

}

2)、运行效果

true

6、打印生活在剑桥的交易员的所有交易额

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

 

import streamAPI.entity.Trader;

import streamAPI.entity.Transaction;

 

public class TestStreamAPI8 {

   

    private static Trader raoul = new Trader("Raoul","Cambridge");

    private static Trader mario = new Trader("Mario","Milan");

    private static Trader alan = new Trader("Alan","Cambridge");

    private static Trader brian = new Trader("Brian","Cambridge");

   

    private static List<Transaction> transactions = Arrays.asList(

            new Transaction(brian,2011,300),

            new Transaction(raoul,2012,1000),

            new Transaction(raoul,2011,400),

            new Transaction(mario,2012,710),

            new Transaction(mario,2012,700),

            new Transaction(alan,2012,950)

    );

    /**

     * 打印生活在剑桥的交易员的所有交易额

     */

    public static void test6() {

        Optional<Integer> res = transactions.stream().

            filter((t)->t.getTrader().getCity().equals("Cambridge")).

            map(Transaction::getValue).

            reduce(Integer::sum);

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

    }

   

   

    public static void main(String[] args) {

        test6();

    }

}

2)、运行效果

2650

7、所有交易中,最高的交易额是多少

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

 

import streamAPI.entity.Trader;

import streamAPI.entity.Transaction;

 

public class TestStreamAPI8 {

   

    private static Trader raoul = new Trader("Raoul","Cambridge");

    private static Trader mario = new Trader("Mario","Milan");

    private static Trader alan = new Trader("Alan","Cambridge");

    private static Trader brian = new Trader("Brian","Cambridge");

   

    private static List<Transaction> transactions = Arrays.asList(

            new Transaction(brian,2011,300),

            new Transaction(raoul,2012,1000),

            new Transaction(raoul,2011,400),

            new Transaction(mario,2012,710),

            new Transaction(mario,2012,700),

            new Transaction(alan,2012,950)

    );

   

    /**

     * 所有交易中,最高的交易额是多少

     */

    public static void test7() {

        Optional<Integer> res = transactions.stream().

                map((t)->t.getValue()).

                max(Integer::compare);

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

           

    }

    public static void main(String[] args) {

        test7();

    }

}

2)、运行效果

1000

8、找到交易额最小的交易

1)、代码实现

package streamAPI;

 

import java.util.Arrays;

import java.util.List;

import java.util.Optional;

 

import streamAPI.entity.Trader;

import streamAPI.entity.Transaction;

 

public class TestStreamAPI8 {

    

     private static Trader raoul = new Trader("Raoul","Cambridge");

     private static Trader mario = new Trader("Mario","Milan");

     private static Trader alan = new Trader("Alan","Cambridge");

     private static Trader brian = new Trader("Brian","Cambridge");

    

     private static List<Transaction> transactions = Arrays.asList(

              new Transaction(brian,2011,300),

              new Transaction(raoul,2012,1000), 

              new Transaction(raoul,2011,400),

              new Transaction(mario,2012,710),

              new Transaction(mario,2012,700),

              new Transaction(alan,2012,950)

     );

     /**

      * 找到交易额最小的交易

      */

     public static void test8() {

         Optional<Transaction> res = transactions.stream().

              min((t1,t2)->Integer.compare(t1.getValue(),t2.getValue()));

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

     }

    

     public static void main(String[] args) {

         test8();

     }

}

2)、运行效果

Transaction [trader=Trader [name=Brian, city=Cambridge], year=2011, value=300]

 

第九节:并行流与顺序流

一、并行流

1、并行流概念

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流;

Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作。StreamApi可以声明性的通过parallel()与sequential()在并行流与串行流之间进行切换;

在学习并行流之前,我们要先了解一个框架,就是fork/join框架;

2、fork/join框架(原始的手段)

Fork/join框架就是在必要的情况下,将一个大任务,进行拆分fork成若干个小任务,拆到不可再拆时,再将一个个的小任务的运算结果进行join汇总,其原理图如下:

该框架的效率是很高的,他采用工作窃取模式(work-stealing):

当执行新的任务时,他可以将其拆分为更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把他放在自己的队列中。

相对于一般的线程池实现,fork/join框架的优势就体现在对其中包含的任务的处理方式上,在一般的线程池中,如果一个线程正在执行的任务由于某种原因无法继续运行,那么该线程会处于等待状态,而在foek/join框架实现中,

如果某个子问题由于等待另外一个子问题的完成而无法继续运行,那么处理该子问题的线程就会主动寻找其他尚未运行的问题来执行,这种方式减少了线程的等待时间,提高了性能;

3、fork/join框架示例演示

1)、代码实现

package streamAPI;

 

import java.util.concurrent.RecursiveTask;

 

public class ForkJoinTest extends RecursiveTask<Long> {

   

    private static final long serialVersionUID = 1L;

 

    private long start;

   

    private long end;

   

    public ForkJoinTest(long start, long end) {

        super();

        this.start = start;

        this.end = end;

    }

 

    private static final long THRESHOLD = 10000;

   

    @Override

    protected Long compute() {

       

        long length = end - start;

       

        if(length<=THRESHOLD) {

            long sum = 0;

            for(long i = start;i<=end;i++) {

                sum +=i;

            }

            return sum;

        }else {

            long middle = (start+end)/2;

            ForkJoinTest left = new ForkJoinTest(start,middle);

            left.fork();//拆分子任务,同时压入线程队列

           

            ForkJoinTest right = new ForkJoinTest(start,middle);

            right.fork();

           

            return left.join()+right.join();

        }

    }

}

 

package streamAPI;

 

import java.time.Duration;

import java.time.Instant;

import java.util.concurrent.ForkJoinPool;

import java.util.concurrent.ForkJoinTask;

 

public class ForkJoinRun {

 

    public static void main(String[] args) {

        Instant start = Instant.now();

        ForkJoinPool pool = new ForkJoinPool();

        ForkJoinTask<Long> task = new ForkJoinTest(0,100000000L);

        Long sum = pool.invoke(task);

        System.out.println(sum);

        Instant end = Instant.now();

        System.out.println("耗费时间为:"+Duration.between(start, end).toMillis());

    }

}

2)、运行效果

305174216704

耗费时间为:79

3)、分析

这里就不和普通的for循环进行对比啦,数据量小的话,因为for循环走的是底层,他会更直接更快一点,数据量十分巨大的话,框架的优势就显示出来了,这个就像hadoop一样,数据小的话是不建议用的;

另外,我们可以看出来,他这个框架的用法其实很复杂的,所以在java8中就引入了一个全新的并行流,我们来看一下他到底有多简化;

4、java8并行流示例演示

1)、代码实现

package streamAPI;

import java.time.Duration;

import java.time.Instant;

import java.util.concurrent.ForkJoinPool;

import java.util.concurrent.ForkJoinTask;

import java.util.stream.LongStream;

public class ForkJoinRun {

    public static void main(String[] args) {

        test2();

    }

    public static void test2() {

        Instant start = Instant.now();

        LongStream.rangeClosed(0,10000000000L).parallel().reduce(0,Long::sum);

        Instant end = Instant.now();

        System.out.println("耗费时间为:"+Duration.between(start, end).toMillis());

    }

}

2)、运行效果

耗费时间为:1707

3)、分析

从运行结果上看,他还快了点呢,这说明他底层封装的比我们自己写的好多了,哈哈,其实他底层封装的就是fork/join,但是你看现在这个封装后的结果,使用起来就非常的便捷了,

并且在并行与串行之间,还可以来回的切换,所以说,在处理大数据的时候,java8还是很给力的,你可以直接先并行,再map-reduce一下;

至于串行流,这里就不回顾了,前面几节课我们讲了半天的串行流啦;

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值