java8新特性-Stream入门学习

本文深入解析Java8中的Stream API,涵盖Stream的创建、常见操作如过滤、映射、排序,以及归约和收集等高级功能。通过实例演示如何高效处理数据集合,提升代码简洁性和性能。

上一篇介绍了Lambda的学习,如果对Lambda表达式还不清晰的同学可以戳一下这个链接:java8新特性-lambda表达式入门学习。java8除了提供了Lambda表达式,操作集合的Stream API也是非常新特性中最值得学习和掌握的,它大大简化了,我们操作数据集合的代码量的书写。简单来说Stream是一个抽象概念,可以通过查找,过滤,映射等操作,这一点与Scala中集合操作很类似。

Stream是什么?

通俗的说就是操作数据集合的一种手段,你可以使用它,以获取所需要的集合数据源类型,如下图所示:
通常Stream流操作整个流程是创建流对象->对流操作->获得目标数据源操作
Stream

创建Stream

  • 通过Collection接口提供的Stream
  1. 返回一个顺序流
default Stream<E> stream() {
   return StreamSupport.stream(spliterator(), false);
 }
  1. 返回一个并行流
default Stream<E> parallelStream() {
  return StreamSupport.stream(spliterator(), true);
}

那我们简单演示一下这两个流的使用。

  • Emplyee的基本实体类
package com.codegeek.lambda;
import lombok.*;

@Setter
@Getter
@NoArgsConstructor
@ToString
public class Employee {
    /**
     * 员工姓名
     */
    private String name;
    /**
     * 员工年龄
     */
    private int age;
    /**
     * 基本薪水
     */
    private double basicSalary;

    /**
     * 订单成交总额
     */
    private double dealTotalPrice;

    public Employee(String name, int age, double basicSalary,double dealTotalPrice) {
        this.name = name;
        this.age = age;
        this.basicSalary = basicSalary;
        this.dealTotalPrice = dealTotalPrice;
    }

    /**
     * 员工总薪资=基本薪资+提成薪资
     *
     * @return Double
     */
    public Double getTotalSalary() {
        return this.basicSalary + this.dealTotalPrice * 0.04;
    }
}

测试方法如下:

 @Test
 public void test() {
	Employee qingLong = new Employee("青龙", 25, 5500, 7500);
	Employee baiHu = new Employee("白虎", 27, 5000, 9000);
	Employee zhuQue = new Employee("朱雀", 22, 3800, 4500);
	Employee xuanWu = new Employee("玄武", 24, 3300, 3300);
	List<Employee> employees = Arrays.asList(qingLong, baiHu, zhuQue, xuanWu);
	// 得到一个顺序流,并获取工资大与4000的员工的姓名
	Stream<Employee> stream = employees.stream();
    stream.filter(e-> e.getTotalSalary()>4000).map(Employee::getName).forEach(System.out::println); 
    // 得到一个并行流,获取年龄大于25的员工姓名
    Stream<Employee> employeeStream = employees.parallelStream();
    employeeStream.filter(employee -> employee.getAge()> 25).map(Employee::getName).forEach(System.out::println ); 
}
  • 通过Arrays创建Stream流
    注意数组里面是什么类型的数组,就会产生同类型的流。
  1. 产生IntStream
public static IntStream stream(int[] array) {
   return stream(array, 0, array.length);
}
  1. 产生LongStream
public static LongStream stream(long[] array) {
 return stream(array, 0, array.length);
}
  1. 产生DoubleStream
 public static DoubleStream stream(double[] array) {
   return stream(array, 0, array.length);
}

下面简单演示以下IntStream的使用案列

// 初始化一个数组对象
 int[] arr = {11, 55, 44, 20, 45, 16};
// 通过Arrays创建流对象是IntStream
 Arrays.stream(arr).sorted().forEach(System.out::println);

Stream常见的操作

上面简单介绍了下,流的创建,当流创建好后,我们又该如何使用呢,常见流的操作如下?

  • 过滤和切片
方法方法介绍
filter(Predicate<? super T> predicate)接收断言接口,并从流中排除元素
distinct()去除流中重复的元素
limit(long maxSize)截取流中元素个数,类似sql查询limit
skip(long n)跳过元素,跳过前n个元素

使用演示:

@Test
public void testFilter() {
  int[] age = {11, 22, 44, 22, 24, 24, 66, 77, 77, 25, 34};
   // 使用filter过滤获得大于33的数组元素
  Arrays.stream(age).filter(i -> i > 33).forEach(System.out::println);
  // 去重
  Arrays.stream(age).distinct().forEach(System.out::println);
  // 截取3个元素
  Arrays.stream(age).limit(3).forEach(System.out::println);
  // 跳过前3个元素
  Arrays.stream(age).skip(3).forEach(System.out::println);  
}
  • 映射
方法方法介绍
map(Function mapper)接收一个函数式接口,将会映射到流中的每一个元素
mapToDouble(ToDoubleFunction mapper)接收函数式接口,将映射产生DoubleStream
mapToLong(ToLongFunction mapper)接收函数式接口,将映射产生LongStream
mapToInt(ToIntFunction mapper)接收函数式接口,将映射产生IntStream
flatMap(Function extends Stream mapper)接收函数,将流中的每个值都转换一个流,然后将这些流汇成一个流

使用演示:

   String[] arr = {"java", "scala", "php", "python", "c++"};
   // 将流中的每一个元素转换成大写
   Arrays.stream(arr).map(String::toUpperCase).forEach(System.out::println);
   //将流中的数据转Double类型
    long[] array = {1, 4, 6, 7, 12};
   // 返回Double类型的Stream
   Arrays.stream(array).mapToDouble(e-> e* 100).forEach(System.out::println);
   // 返回Long类型的Stream
   Arrays.stream(array).mapToLong(e -> e + 23).forEach(System.out::println);
   // flatMap演示
  List<List<String>> database = new ArrayList<>();
  List<String> noSql = Arrays.asList("redis", "hbase", "membercache");
  List<String> sql = Arrays.asList("mysql", "oracle", "db2");
  database.add(noSql);
  database.add(sql);
  List<String> h = database.stream().flatMap(s -> s.stream().filter(si -> si.contains("h"))).collect(Collectors.toList());
  h.stream().forEach(System.out::println);
  • 排序
    排序相对简单,以之前定义的employee类如下:
Employee qingLong = new Employee("青龙", 25, 5500, 7500);
Employee baiHu = new Employee("白虎", 27, 5000, 9000);
Employee zhuQue = new Employee("朱雀", 22, 3800, 4500);
Employee xuanWu = new Employee("玄武", 24, 3300, 3300);
List<Employee> employees = Arrays.asList(qingLong, baiHu, zhuQue, xuanWu);
// 按照薪水的大小进行排序
 employees.stream().sorted(Comparator.comparing(Employee::getTotalSalary)).forEach(System.out::println);
  • 查找与匹配
方法方法介绍
allMatch(Predicate p)检查流中的元素是否都匹配
anyMatch(Predicate p)检查是否匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回流中任意元素
count返回流中的个数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值

方法演示:以初始化的员工类

// 判断所有的员工年龄是否大于18
boolean b = employees.stream().allMatch(e -> e.getAge() > 18);
System.out.println("allMatch="+b);// 结果为true
// 判断所有员工中有没有年龄大于35的
boolean b1 = employees.stream().anyMatch(e -> e.getAge() > 35);
System.out.println("anyMath=" + b1); // 结果为false
// 判断所有员工中没有年龄大于35的
boolean b1 = employees.stream().noneMatch(e -> e.getAge() > 35);
System.out.println("anyMath=" + b1); // 结果为true
// 返回第一个员工的信息
Optional<Employee> first = employees.stream().findFirst();
System.out.println(first.get());
// 统计年龄大于20的员工个数
ong count = employees.stream().filter(e -> e.getAge() > 20).count();
System.out.println("count="+count);
// 统计集合中员工薪资最高的员工信息
Optional<Employee> max = employees.stream().max(Comparator.comparing(Employee::getTotalSalary));
System.out.println("max=" + max);
  • 归约
方法方法介绍
reduce(BinaryOperator p)将流中的元素反复结合起来得到一个值返回Optional
reduce(T iden,BinaryOperator p)将流中的元素反复结合起来得到一个值T

演示:

Optional<Double> reduce = employees.stream().map(Employee::getTotalSalary).reduce(Double::sum);
double v = reduce.get();
System.out.println("reduce="+v);
int[] array = {1, 4, 6, 7, 12};
System.out.println("====");
// 这里第一次将0作为x的值然后数组中1作为y,然后计算后的结果是1,第二次将1作为x的值,然后数组中的4作为y值进行相加,后面以此类推,直到将所有的值都进行相加
int reduce = Arrays.stream(array).reduce(0, (x, y) -> x + y);
System.out.println("reduce=" + reduce);
  • 收集
方法方法介绍
collect(Collector c)将流转换为其他形式,接收Collector接口实现。

下面将对Stream做一个总体的回顾和使用。


    @Test
    public void test() {
        // 避免空指针异常
        Optional<Employee> optional = employees.stream().sorted((e1, e2) -> e1.getTotalSalary().compareTo(e2.getTotalSalary())).findFirst();
        // 若空指针异常就怎么处理
        optional.orElse(new Employee());
        System.out.println(optional);

        // 返回任意一个(并行开启多个线程查找)
        Optional<Employee> any = employees.parallelStream().filter((e) -> e.getAge() > 25).findAny();
        System.out.println(any);

        // Max(Comparator按年龄比较)
        Optional<Employee> max = employees.stream().max(Comparator.comparing((e) -> e.getAge()));
        System.out.println(max);
        Optional<Double> max1 = employees.stream().map(Employee::getTotalSalary().max(Double::compare);
        System.out.println(max1.get());

        // 流中元素接收,计算得到一个
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        Integer reduce = list.stream().reduce(0, (x, u) -> x + u);//0+1+2.....+10
        System.out.println(reduce);

        Optional<Integer> reduce1 = employees.stream().map(Employee::getAge).reduce(Integer::sum);
        System.out.println(reduce1.get() + "----------");

        // 收集元素到list
        employees.stream().map(Employee::getName).distinct().collect(Collectors.toList()).forEach(System.out::println);
        System.out.println();
        // 收集元素到LinkList
        employees.stream().map(Employee::getName).distinct().collect(Collectors.toCollection(HashSet::new)).forEach(System.out::println);

        // 获取流中最大值
        Optional<Integer> max2 = employees.stream().map(Employee::getAge).max(Integer::compare);
        System.out.println(max2.get());

        // 收集获取总数(集合总数)
        Long collect = employees.stream().collect(Collectors.counting());
        System.out.println(collect);

        // 工资的平均值
        Double collect1 = employees.stream().collect(Collectors.averagingDouble(Employee::getTotalSalary));
        System.out.println(collect1);

        // 获取工资的总数,综合,最小值,平均值,最大值
        DoubleSummaryStatistics collect2 = employees.stream().collect(Collectors.summarizingDouble(Employee::getTotalSalary));
        System.out.println(collect2);

        // 获取年龄最大的员工
        Optional<Employee> collect3 = employees.stream().collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())));
        System.out.println(collect3.get());

        // 获取年龄最小的员工
        Optional<Double> collect4 = employees.stream().map(Employee::getTotalSalary).collect(Collectors.minBy(Double::compare));
        System.out.println(collect4.get());

        // 按薪资分组
        Map<Double, List<Employee>> collect5 = employees.stream().collect(Collectors.groupingBy(Employee::getTotalSalary));
        System.out.println(collect5);

        // 薪资分区(匹配true)
        Map<Boolean, List<Employee>> collect6 = employees.stream().collect(Collectors.partitioningBy((e) -> e.getTotalSalary() > 5000d));
        System.out.println(collect6);
    }

到这里Stream介绍基本完成了,下一篇让我学习以下jdk8的Optional类的学习。

STM32是一款基于ARM Cortex-M内核的微控制器,广泛应用于嵌入式系统设计中。在许多实际应用中,我们可能需要使用STM32的模拟数字转换器(ADC)进行信号采集,然后通过数模转换器(DAC)将数字信号转化为模拟信号输出。本文将深入探讨STM32 ADC采集与DAC输出的相关知识点。ADC是STM32中的一个重要组成部分,它负责将外部的模拟电压信号转换为数字值。STM32系列通常包含多个ADC通道,每个通道可以连接到不同的输入信号源。ADC的转换速率是衡量其性能的关键指标,描述中提到的最大采集频率为700Hz,意味着STM32的ADC在该频率下可以保证不失真地完成采样。超过这个频率,由于采样定理,可能无法准确捕获输入信号的全部信息,导致失真或信息丢失。DAC则是将数字信号转换回模拟信号的设备,常用于音频输出、波形生成等场景。STM32的DAC模块也支持多个通道,并且能够设置输出电压范围,以适应不同的应用需求。在描述中,当ADC采集频率超过4kHz时,打点不完全,这可能是因为DAC输出无法跟上ADC的采样速度,导致输出的模拟信号质量下降。STM32的ADC和DAC操作涉及以下几个关键步骤:1. **配置ADC**:包括选择合适的ADC通道、设置转换分辨率(如12位)、设置采样时间、启动模式(单次转换或连续转换)以及设置中断或DMA传输。2. **配置DAC**:设定DAC通道、输出电压范围、触发源(如软件触发、定时器触发等)和工作模式(单缓冲或双缓冲)。3. **同步ADC与DAC**:在实时应用中,确保ADC采集到的数据能及时传送到DAC进行输出,可能需要精确的时间同步,或者通过DMA来实现数据的无缝传输。4. **数据处理**:ADC采集到的数据可能需要进行滤波、增益调整等预处理,然后再送到DAC。对于高速采集,可以考虑使用DMA将ADC的转换结果直接送入内存,减轻CPU负担。5. **错误处理与调试**:在实际应用中,需要监控ADC和DAC的工作状态,例如检测转换错误、溢出错误等,以便及时发现并解决问题。在“STM32 ADC与DAC实验 无DMA传输”这个实验中,我们可能关注的是如何在没有使用DMA的情况下,通过CPU控制将ADC采集的数据实时传递给DAC。这通常会增加CPU的负担,因为需要不断读取ADC的结果并写入DAC。为了提高效率,可以优化中断处理、合理安排任务调度,或者在特定的应用场景下,适当降低ADC的采样速率以匹配DAC的输出能力。STM32的ADC和DAC功能是其在嵌入式系统设计中处理模拟信号的关键。正确配置和使用这两个模块,能实现高效、高质量的信号转换,满足各种实际应用需求。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值