java8新特性之Stream API

简介: Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询语句一样简单。也可以使用 Stream API 来并行执行操作。

java8新特性之Stream API

一.概述

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询语句一样简单。也可以使用 Stream API 来并行执行操作。
简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式,它可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

特点:

    1 . Stream 自己不会存储元素
    2. Stream 不会改变数据源对象,相反,它会返回一个持有结果的新Stream
    3. Stream  惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算。

二、本文预备工作

1.实体类

员工实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Objects;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {

    private Integer id;
    private String name;
    private Integer age;
    private double salary;
    private Status status;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age.equals(employee.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(age);
    }

    public enum Status{
        FREE,
        BUSY,
        VOCATION
    }
}

2.员工List

 List<Employee> emps = Arrays.asList(
            new Employee(101, "zhangsan", 19, 3333.33, Employee.Status.BUSY),
            new Employee(102, "zhangsan1", 20, 5555.55,Employee.Status.FREE),
            new Employee(104, "zhangsan2", 30, 6666.66,Employee.Status.BUSY),
            new Employee(105, "zhangsan3", 50, 8888.88,Employee.Status.BUSY),
            new Employee(106, "zhangsan4", 30, 6666.66,Employee.Status.VOCATION),
            new Employee(107, "zhangsan5", 50, 8888.88,Employee.Status.VOCATION)
    );

三、Stream的操作三个步骤

1.创建Stream

一个数据源(如:集合,数组),获取一个流

1.1 可以通过Collecttion系统集合提供的stream()或parallelStream()

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

1.2 通过Arrays中的静态方法stream()获取数组流

Employee [] emps = new Employee[10];
Stream<Employee> stream = Arrays.stream(emps);

1.3 通过Stream 类中的静态方法 of()、iterate()、generate()

  //通过Stream 类中的静态方法of()
 Stream<String> stream3 = Stream.of("aa","bb","cc")
 
 //创建无限流
   //迭代
   Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
    stream4.limit(10).forEach(System.out::println);
  //生成
  Stream.generate(()->Math.random())
        .limit(5)
        .forEach(System.out::println);

1.4 使用 Pattern.splitAsStream() 方法,将字符串分隔成流

Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d,e");
stringStream.forEach(System.out::println);

2.中间操作

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

2.1 筛选与切片:

**filter**---接收Lambda,从流中排除某些元素
**limit**----截断流,使其元素不超过给定数量
**skip(n)**---跳过流,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流,与limit(n)互补
**distinck** ---筛选,通过流所生成元数的hashCode()和equals()去除重复元素
 

2.2 映射:
map--接收lambda,将元素转换成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每一个元数上,并将其映射成一个新的元素
flatMap--接收一个函数作为参数,将流中每个值都换成另一个流,然后把所有流连接成一个流

2.3 排序
sorted()--自然排序(compareble---compareTo)
sorted(Compartor com)--定制排序(comparator)

测试代码如下:

    /**
 * 一.Stream 的三个操作步骤
 * 1.创建Stream流
 * <p>
 * 2.中间操作
 * <p>
 * 3.终止操作
 */
//中间操作
public class StreamTest2 {

    List<Employee> emps = Arrays.asList(
            new Employee(101, "zhangsan", 19, 3333.33, Employee.Status.BUSY),
            new Employee(102, "zhangsan1", 20, 5555.55,Employee.Status.FREE),
            new Employee(104, "zhangsan2", 30, 6666.66,Employee.Status.BUSY),
            new Employee(105, "zhangsan3", 50, 8888.88,Employee.Status.BUSY),
            new Employee(106, "zhangsan4", 30, 6666.66,Employee.Status.VOCATION),
            new Employee(107, "zhangsan5", 50, 8888.88,Employee.Status.VOCATION)
    );
    //中间操作

    /**
     * 筛选与切片
     * filter---接收Lambda,从流中排除某些元素
     * limit----截断流,使其元素不超过给定数量
     * skip(n)---跳过流,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流,与limit(n)互补
     * distinck ---筛选,通过流所生成元数的hashCode()和equals()去除重复元素
     */

    //内部迭代:操作由Stream API完成
    @Test
    public void test1() {
         Stream<Employee> stream = emps.stream()
                                   .filter((e) -> e.getAge() > 20);
         //终止操作
        stream.forEach(System.out::println);
    }
    //外部迭代
    @Test
    public void test2(){
         Iterator<Employee> it = emps.iterator();

         while (it.hasNext()){
             System.out.println(it.next());
         }
    }

    @Test
    public void test3(){
             emps.stream()
                 .filter((e)->{
                     System.out.println("短路!"); //&&  ||
                     return e.getAge()>10;
                 })
                 .limit(2)
                 .forEach(System.out::println);
    }

    @Test
    public void test4(){
        emps.stream()
                .filter((e)->{
                    System.out.println("扔掉前2个!"); //&&  ||
                    return e.getAge()>10;
                })
                .skip(2)
                .distinct()
                .forEach(System.out::println);
    }

    /**
     * 映射
     * map--接收lambda,将元素转换成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每一个元数上,并将其映射成一个新的元素
     * flatMap--接收一个函数作为参数,将流中每个值都换成另一个流,然后把所有流连接成一个流
     * */
    @Test
    public void test5(){
        List<String> list=Arrays.asList("aaa","sss","ddd","fff","ggg");
        list.stream()
                .map((str)->str.toUpperCase())
                .forEach(System.out::println);

        System.out.println("---------------------------------");

        emps.stream()
                .map((e)->e.getName())
                .forEach(System.out::println);
    }

    /**
     * 排序
     * sorted()--自然排序(compareble---compareTo)
     * sorted(Compartor com)--定制排序(comparator)
     * */

    @Test
    public void test6(){
        List<String> list=Arrays.asList("aaa","sss","ddd","fff","ggg");
        list.stream()
                .sorted()
                .forEach(System.out::println);

        System.out.println("--------------------------------------");
        emps.stream()
                .sorted((e1,e2)->{
                    if (e1.getAge().equals(e2.getAge())){
                        return e1.getName().compareTo(e2.getName());
                    }else{
                        return -e1.getAge().compareTo(e2.getAge());
                    }
                })
                .forEach(System.out::println);

    }
}

3.终止操作

一个终止操作,执行中间操作链,并产生结果

3.1 查找与匹配

 ***allMatch**--检查是否匹配所有元素
 * **anyMatch**--检查是否至少匹配一个元素
 * **noneMatch**--检查是否没有匹配所有元素
 * **findFirst**--返回第一个元素
 * **findAny**--返回当前流中的任意元素
 * **count**--返回流中元素的总个数
 * **max**--返回流中最大值
 * **min**--返回流中最小值

代码如下(示例):

@Test
    public void test01() {
        boolean b1 = emps.stream()
                .allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b1);

        System.out.println("--------------------------------------");
        boolean b2 = emps.stream()
                .anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b2);

        System.out.println("--------------------------------------");
        boolean b3 = emps.stream()
                .noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b3);

        Optional<Employee> op = emps.stream()
                .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                .findFirst();
        System.out.println(op.get());
        System.out.println("-------------------------------------------");
        Optional<Employee> opany = emps.stream()
                .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
                .findAny();
        System.out.println(opany.get());

        System.out.println("-------------------------------------------");
        long count = emps.stream()
                .count();
        System.out.println(count);

        System.out.println("-------------------------------------------");
        Optional<Employee> max = emps.stream()
                .max((e1, e2) -> e1.getAge().compareTo(e2.getAge()));
        System.out.println(max.get().getAge());

        System.out.println("-------------------------------------------");
        Optional<Integer> min = emps.stream()
                .map(Employee::getAge)
                .min(Double::compare);
        System.out.println(min.get());
    }

3.2 归约

  **reduce(T identity,BinaryOperator) / reduce(BinaryOperator)** --可以将流中元素反复结合起来,得到一个值
/**
     * 归约
     * reduce(T identity,BinaryOperator) / reduce(BinaryOperator) --可以将流中元素反复结合起来,得到一个值
     * */
    @Test
    public void test02(){
        List<Integer> list =Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer reduce = list.stream()
                             .reduce(0, (x, y) -> x + y);
        System.out.println(reduce);
        System.out.println("---------------------------------------");
        Optional<Double> reduce1 = emps.stream()
                                       .map(Employee::getSalary)
                                       .reduce(Double::sum);
        System.out.println(reduce1.get());
    }

3.3 收集

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

collector 接口中方法的实现决定了如何对溜执行收集操作(如收集到List,set,Map)。但是Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例。

3.3.1 toList(), toSet(), toCollection()

@Test
    public void test03(){
         List<String> list = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);
        System.out.println("-------------------------------------");

         Set<String> set = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
         set.forEach(System.out::println);
        System.out.println("----------------------------------------");

         HashSet<String> hashSet = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
         hashSet.forEach(System.out::println);

    }

3.3.2 counting(),averagingDouble(),summingDouble(),maxBy()和minBy()

 @Test
    public void test04(){
        //总数
         Long count = emps.stream()
                .collect(Collectors.counting());
        System.out.println(count);
        System.out.println("----------------------------------------");
        
        //平均值
         Double ave = emps.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(ave);
        System.out.println("----------------------------------------");
        
        //总和
        Double sum = emps.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(sum);
        System.out.println("----------------------------------------");
        
        //最大值
        Optional<Employee> max = emps.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(max.get());
        System.out.println("----------------------------------------");
        
        //最小值
        Optional<Double> min = emps.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(min.get());
    }

3.3.3 分组,多级分组和分区

    //分组
    @Test
    public void test05() {
        Map<Employee.Status, List<Employee>> map = emps.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));

         Iterator<Map.Entry<Employee.Status, List<Employee>>> iterator = map.entrySet().iterator();
         while (iterator.hasNext()){
             System.out.println(iterator.next());
         }
    }
    //多级分组
    @Test
    public void test06() {
         Map<Double, Map<String, List<Employee>>> collect1 = emps.stream()
                .collect(Collectors.groupingBy(Employee::getSalary, Collectors.groupingBy((e) -> {
                    if (e.getAge() <= 35) {
                        return "青年";
                    } else if (e.getAge() <= 50) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));

         Iterator<Map.Entry<Double, Map<String, List<Employee>>>> it= collect1.entrySet().iterator();
         while (it.hasNext()){
             System.out.println(it.next());
         }
    }

    //分区
    @Test
    public void test07() {
         Map<Boolean, List<Employee>> collect = emps.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() > 6000));
         Iterator<Map.Entry<Boolean, List<Employee>>> iterator = collect.entrySet().iterator();
         while (iterator.hasNext()){
             System.out.println(iterator.next());
         }
    }
目录
相关文章
|
4天前
|
Java API 数据中心
百炼平台Java 集成API上传文档到数据中心并添加索引
本文主要演示阿里云百炼产品,如何通过API实现数据中心文档的上传和索引的添加。
|
4天前
|
Java API 开发者
|
3天前
|
并行计算 Java API
|
5天前
|
机器人 API Python
智能对话机器人(通义版)会话接口API使用Quick Start
本文主要演示了如何使用python脚本快速调用智能对话机器人API接口,在参数获取的部分给出了具体的获取位置截图,这部分容易出错,第一次使用务必仔细参考接入参数获取的位置。
|
3天前
|
XML JSON API
RESTful API设计最佳实践:构建高效、可扩展的接口
【8月更文挑战第17天】RESTful API设计是一个涉及多方面因素的复杂过程。通过遵循上述最佳实践,开发者可以构建出更加高效、可扩展、易于维护的API。然而,值得注意的是,最佳实践并非一成不变,随着技术的发展和业务需求的变化,可能需要不断调整和优化API设计。因此,保持对新技术和最佳实践的关注,是成为一名优秀API设计师的关键。
|
4天前
|
监控 API 数据安全/隐私保护
​邮件API触发式接口分析?邮件API接口好评榜
邮件API在企业通信和营销中至关重要,通过自动化邮件发送流程提升效率与客户满意度。本文解析邮件API触发式接口,即基于特定事件(如用户注册、购买产品)自动发送邮件的技术,能显著加快企业响应速度并增强用户体验。推荐市场上的优秀邮件API产品,包括SendGrid、Mailgun、Amazon SES、Postmark及新兴的AOKSend,它们各具特色,如高发送率、详细分析工具、灵活配置、强大的日志功能及用户友好的API接口,帮助企业根据不同需求选择最合适的邮件API解决方案。
|
12天前
|
存储 算法 Oracle
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
39 8
|
21天前
|
开发框架 前端开发 JavaScript
循序渐进VUE+Element 前端应用开发(13)--- 前端API接口的封装处理
循序渐进VUE+Element 前端应用开发(13)--- 前端API接口的封装处理
|
28天前
|
缓存 自然语言处理 搜索推荐
解析微店商品详情的 API 接口获取之道
在电商蓬勃发展的时代,微店的商品详情数据对商家与开发者极具价值。API接口成为挖掘这些数据的关键,助力商家洞察市场,优化策略,实时监控竞品,管理库存;赋能开发者创新,如构建推荐系统和分析工具。获取接口需注册认证,理解政策,明确权限需求。调用API须精读文档,选用合适语言编码,处理错误,优化策略如缓存和异步请求。数据处理涉及自然语言分析、价格预测和情感分析,应用广泛。注意事项包括合规操作、数据安全、适应接口变动及性能优化,确保高效合法利用数据,推动电商进步。
|
28天前
|
API 数据安全/隐私保护 开发者
Web 开发新风尚!Python RESTful API 设计与实现,让你的接口更懂开发者心!
【7月更文挑战第23天】Python的RESTful API设计在Web开发中流行,提升效率与体验。REST强调HTTP方法(GET, POST, PUT, DELETE)操作资源。使用Flask框架可快速实现API,如管理用户信息。示例代码展示如何创建、读取、更新和删除用户,通过不同HTTP方法和URL路径。实际应用中,增加验证、错误处理和权限控制可增强API的安全性和稳定性。安装Flask后,可运行代码测试API功能。
53 6