逸学java【初级菜鸟篇】9.3 Stream流

21 篇文章 0 订阅
13 篇文章 0 订阅

hi,我是逸尘,一起学java吧


得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念(就是都基本使用lambda的形式)。

流处理

我们首先理解什么是流处理,它类似于sql语句,可以执行非常复杂的过滤,映射,查找,收集等功能,且代码很少,但是可读性不高。字如其名,它的处理如同流淌的水一样,或者可以理解为流水线一样。

Stream流

Stream流也是流处理的一种,大多数流处理都是在Stream接口处理的,它是一个泛接口,所以它可以操作的元素是任意对象,他的操作可以用lambda去书写(推荐)。

生成Stream流

Stream操作集合和数组的第一步是得到(生成)Stream流。

在Collection接口默认方法是stream()生成流。

 在数组中使用Arrays.stream(数组) /或Stream.of(数组);

 中间操作方法

其次我们就可以使用中间操作来处理这些元素对象。

这里举出一些常见的API

  • forEach : 逐一处理(遍历)
  • count:统计个数
  • filter : 过滤元素 【数据过滤】
  • distinct:去除重复元素 【数据过滤】
  • limit : 取前几个元素 【数据过滤】
  • skip : 跳过前几个 【数据过滤】
  • map : 加工方法 【数据映射】
  • allMatch:判断流中的元素是否会全部符合某一个条件 【数据查找】
  • concat:合并流

终结操作方法

终结操作方法调用以后流就无法使用了它是流的最后一个过程。

常见的有API有

单独保存的操作方法

  • collect() 方法配合collectors类将流的结果进行保存

处了stream流本身的方法我们还有两个可以协助流操作的类

Collectors类

collectors是一个收集器类,可以将Stream流对象进行封装,归集,分组,是数据的收集,筛选出特殊的数据,可以复杂的统计。

1.toList()将流元素封装到List集合 toSet() toMap()类似

2.toCollection(Supplier<C> collectionFactory) 将流中的元素收集到指定类型的集合中的方法

即一个类型为 Supplier<C> 的函数式接口,其中 C 是要创建的集合类型。例如,如果我们想要创建一个 LinkedList 集合,可以这样使用该方法: 

List<Integer> list = Stream.of(1, 2, 3, 4, 5)
    .collect(Collectors.toCollection(LinkedList::new));

3.groupingBy(Function<? super T, ? extends K> classifier) 

  • 一个函数式接口 classifier,表示如何对流中的元素进行分类。

例如,我们有一个字符串列表,并希望按照字符串长度分组:

List<String> list = Arrays.asList("apple", "banana", "peach", "grape","pear");
Map<Integer, List<String>> map = list.stream().collect(Collectors.groupingBy(String::length));

 在上面的代码中,我们使用 String::length 函数式接口将字符串转换为它的长度,并将其作为分类键。运行结果如下:

{4=[pear], 5=[apple, peach,grape], 6=[banana]}

需要注意的是,groupingBy() 方法返回的是一个 Map 对象,其中键是分类键.

Collectors.groupingBy() 方法还提供了第二个参数 downstream,用于进一步对分组的结果进行处理。例如,我们可以使用 Collectors.counting() 方法统计每个分组中元素的数量:

Map<Integer, Long> map = list.stream()
    .collect(Collectors.groupingBy(String::length, Collectors.counting()));

上面的代码中,我们使用 Collectors.counting() 方法作为 downstream 参数,统计了每个分组中元素的数量,并将结果封装为 Long 类型。运行结果如下:

{4=1, 5=3, 6=1}

4.toConcurrentMap

将流中的元素收集到一个并发 Map 中的方法

ConcurrentMap<Integer, String> concurrentMap = Stream.of("a", "b", "c")
    .collect(Collectors.toConcurrentMap(
        String::length,
        Function.identity()
    ));

在上面的例子中,我们使用 toConcurrentMap() 方法创建了一个并发 Map,它将字符串的长度作为键,字符串本身作为值。具体来说,这个方法接受两个参数:

一个函数式接口 keyMapper,表示如何将流中的元素转换成键;
一个函数式接口 valueMapper,表示如何将流中的元素转换成值。
对于上述例子中的流,String::length 函数式接口将字符串转换成它的长度,而 Function.identity() 函数式接口则将字符串映射成它本身。因此得到的结果为:

{1=a, 2=b, 3=c}

 5.以及averagingDouble计算元素平均值,maxBy返回符合条件的最大值,joining()按顺序将元素连接成一个String类型数据,counting()统计个数等等

optional类

这是一个容器类

它的主要功能是针对NullpointerException空指针异常做处理,可以保证保存的值不为null。

of()返回一个value值等于参数的optional实例

ofNullable()是返回一个value值等于非null参数的optional实例

filter()是给定条件值匹配

empty()是静态方法,返回一个空值的optional实例

案例 

我们上面的中间操作,其实是对我们的数据源进行加工。

这里我们简单做了一个去重        

package com.yd.yc;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Thirteen {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(6,88,4,5,22,22,6,66,7);
        //原数据
        printeach(list);
        //获取stream,去重,收集器类重新封装
        List<Integer> collect = list.stream().distinct().collect(Collectors.toList());
        printeach(collect);
    }
        //遍历方法
    private static void printeach(List<Integer> list) {
        System.out.println("集合内容"+list);
        //逐一处理(遍历)里面是lambda
        list.stream().forEach(n-> System.out.println(n+""));

    }
}

某个公司的部门,分为开财务部门和开发部门,现在需要进行月中数据结算。

创建一张员工

部门姓名年龄月工资性别
开发部张三2815000
开发部李四3520000
开发部王五2918000
财务部赵六3316000
财务部刘七3017000
财务部陈八2714000

对应的是我们的员工实体类

public class Employee {  
    private String name;  
    private int age;  
    private double monthlySalary;  
    private String gender;  
    private String department;  
  
    public Employee(String name, int age, double monthlySalary, String gender, String department) {  
        this.name = name;  
        this.age = age;  
        this.monthlySalary = monthlySalary;  
        this.gender = gender;  
        this.department = department;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public int getAge() {  
        return age;  
    }  
  
    public double getMonthlySalary() {  
        return monthlySalary;  
    }  
  
    public String getGender() {  
        return gender;  
    }  
  
    public String getDepartment() {  
        return department;  
    }  
}

分别筛选出2个部门的最高工资的员工信息,封装成优秀员工对象topperformer

方案A

package com.yd.yc;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class EmployeeTest {
    public static void main(String[] args) {
        Employee employee1 = new Employee("张三", 28, 15000, "男", "开发部");
        Employee employee2 = new Employee("李四", 35, 20000, "女", "开发部");
        Employee employee3 = new Employee("王五", 29, 18000, "男", "开发部");
        Employee employee4 = new Employee("赵六", 33, 16000, "女", "财务部");
        Employee employee5 = new Employee("刘七", 30, 17000, "男", "财务部");
        Employee employee6 = new Employee("陈八", 27, 44000, "女", "财务部");
        //测试
        //System.out.println(employee1.getName());  // 输出:张三
        //System.out.println(employee2.getMonthlySalary());  // 输出:20000.0
        ArrayList<Employee> employeeList = new ArrayList<>();
        employeeList.add(employee1);
        employeeList.add(employee2);
        employeeList.add(employee3);
        employeeList.add(employee4);
        employeeList.add(employee5);
        employeeList.add(employee6);

        //A方案
        //filter是过滤找到符合条件的元素
        //Collectors.maxBy去返回符合条件的最大值,Comparator.comparing(param),param : 这个参数是Function函数式对象,默认大,Comparator.reverseOrder()默认倒序
        Optional<Employee> result = employeeList.stream()
                .filter(e -> "开发部".equals(e.getDepartment()))
                .collect(Collectors.maxBy(Comparator.comparing(Employee::getMonthlySalary)));
        //返回一个实体类对象
        Employee employee = result.get();
        System.out.println(employee.getName());

        //第二种写法
        Employee  resultOne= employeeList.stream().filter(e -> "财务部".equals(e.getDepartment()))
                .max((o1, o2) -> Double.compare(o1.getMonthlySalary(), o2.getMonthlySalary())).get();
        //必须重写toString才可以有内容
        System.out.println(resultOne);
        System.out.println(resultOne.getMonthlySalary());
        //包装在一个优秀员工里
        List<Employee> topEmployees = new ArrayList<>();
        topEmployees.add(resultOne);
        topEmployees.add(employee);
        System.out.println(topEmployees);
        
    }
}

 方案B

        //B方案
        Map<String, List<Employee>> groupedByDepartment = employeeList.stream()
                //分组
                .collect(Collectors.groupingBy(Employee::getDepartment));


        List<Employee> topEmployees = new ArrayList<>();

        for (List<Employee> departmentEmployees : groupedByDepartment.values()) {
            Employee topEmployee = departmentEmployees.stream()
                    .max(Comparator.comparingDouble(Employee::getMonthlySalary))
                    //注意,如果一个部门没有员工,那么这个方法将返回null
                    //该方法在给定的流中找不到元素时返回一个默认值。
                    .orElse(null);
            if (topEmployee != null) {
                topEmployees.add(topEmployee);
            }
        }
        System.out.println(topEmployees);

我们要注意的是stream流是方便操作集合/数组的手段,集合/数组才是开发中的目的。

  • 11
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员逸尘

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

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

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

打赏作者

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

抵扣说明:

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

余额充值