Java8 新特性-Stream流介绍

本文详细介绍了Java Stream API的使用,展示了如何通过Stream操作简化集合处理,提升代码的清晰性和效率。涉及filter、map、limit、sorted等核心操作,并结合Employee类和Status枚举实例进行演示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

接下来我将以代码片段的方式对Stream做较为详细的归纳,如需执行文章中讲解的代码,我们需要3个java文件,分别有用Employee雇员类定义、枚举状态定义和JUnit 测试执行类。
文件名为:
Employee.java
Status.java
TestStream.java

Employee.java内容如下:

package com.my.stream;

import java.util.Objects;

public class Employee {
    private String name;
    private Integer age;
    private double salary;
    private Status status;

    public Employee(String name, Integer age, double salary, Status status) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.status = status;
    }

    public Employee(String name, Integer age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    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 boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Employee)) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Double.compare(employee.salary, salary) == 0 &&
                name.equals(employee.name);
    }

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


    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", status=" + status +
                '}';
    }
}

Status.java枚举文件内容如下:

package com.my.stream;

public enum Status {
    FREE,
    BUSY,
    VOCATION,
    ORTHER
}

TestStream.java文件则为本文重点,读者朋友可以从文档中的注解和代码片段了解到Stream流操作的若干知识点:

package com.my.stream;

import org.junit.Test;

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

/*
    作用:对数据进行操作
    条件:需要数据源,集合、数组中的数据
    操作:流水线操作-过滤、筛选、切片、映射...
    结果:对原有数据源不作改变,产生一个新的数据流
    形式: 数据源(创建stream)->filter->map->...->终止操作(产生结果)
 */
public class TestStream {
    //创建stream,4种方法
    @Test
    public void test1() {
        //1、通过Collection系列集合提供的stream()-串行或parallelStream()-并行
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        //2、通过Arrays中的静态方法stream()获取,获得数组流
        String[] arr = new String[10];
        Stream<String> stream2 = Arrays.stream(arr);

        //3、通过Stream类中的静态方法of(),获得数据流
        Stream<String> stream3 = Stream.of("aa", "bb", "cc");

        //4、创建无限流
        //迭代
        Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
        //stream4.limit(10).forEach(System.out::println);
        //System.out.println("===");
        //生成
        Stream<Double> stream5 = Stream.generate(() -> Math.random());
        //stream5.limit(10).forEach(System.out::println);
    }

    List<Employee> emps = Arrays.asList(
            new Employee("张三", 28, 8000, Status.BUSY),
            new Employee("李四", 25, 5000, Status.FREE),
            new Employee("赵六", 33, 14000, Status.FREE),
            new Employee("王五", 33, 9999, Status.FREE),
            new Employee("赵六", 36, 12000, Status.VOCATION)
    );

    //中间操作(形成的流水线中间操作在终止之前不会执行,等到终止操作才会触发,惰性求值)
    @Test
    public void test2() {
        //1、过滤-filter,接收lambda(断言型函数接口),从流中排除某些元素
        Stream<Employee> s1 = emps.stream().filter((e) -> e.getAge() > 28);
        s1.forEach(System.out::println);

        System.out.println("\n===惰性求值==");
        //验证 惰性求值
        Stream<Employee> s2 = emps.stream()
                .filter((e) -> {
                    System.out.println("这是中间操作");
                    return e.getAge() > 28;
                });
        s2.forEach(System.out::println);
        System.out.println("\n===iterator==");
        //由以上的输出可以看出,判断时执行了迭代操作,迭代操作由Stream内部完成,如果需要使用外部迭代则需要迭代器iterate
        Iterator<Employee> it = emps.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }

        System.out.println("\n===limit==");
        //2、截断流-limit(n),使新产生的元素输出不超过指定的数量(满足条件后,之后的迭代操作终止--短路操作提高效率)
        emps.stream().limit(2).forEach(System.out::println);

        System.out.println("\n===skip==");
        //3、跳过元素-skip(n),返回一个扔掉前n个元素的流,若流中不足n个,则返回一个空流,与limit(n)互补
        emps.stream().skip(2).forEach(System.out::println);

        System.out.println("\n===distinct==");
        //筛选-distinct,通过流所产生的元素的hashcode()和equals()去掉重复的元素
        emps.stream().distinct().forEach(System.out::println); //Employee类需重写hashcode()和equals()方法,才能去掉重复

        System.out.println("\n===map==");
        //4、映射-map,接收lambda将元素转换为其他形式或提取信息,接收一个函数作为入参,该函数会被应用到每个元素上,并映射成一个新的元素
        List<String> list = Arrays.asList("aa", "bb", "cc");
        list.stream().map((str) -> str.toUpperCase()).forEach(System.out::println);
        emps.stream().map((e) -> e.getName()).forEach(System.out::println);

        System.out.println("\n===flatmap==");
        //5、映射-flatmap,接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连成一个流
        list.stream().flatMap(TestStream::filterCharacter).forEach(System.out::println);

        //map和flatMap的区别
        //如果使用list.stream().map(TestStream::filterCharacter) 流则变成{{a,a},{b,b},{c,c}}
        //list.stream().flatMap(TestStream::filterCharacter)流则变成{a,a,b,b,c,c}

        System.out.println("\n===sorted自然排序==");
        //6、自然排序-sorted()
        List<String> list2 = Arrays.asList("b", "a", "c");
        list2.stream().sorted().forEach(System.out::println);

        System.out.println("\n===sorted定制排序==");
        //7、定制排序-sorted()
        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);
    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }

    //终止操作
    @Test
    public void test3() {
        //1、匹配-allMatch,检查所有元素是否匹配指定值
        System.out.println("\n===allMatch==");
        boolean b1 = emps.stream().allMatch((e) -> e.getStatus().equals(Status.FREE));
        System.out.println(b1);

        //2、匹配-anyMatch,是否至少匹配一个元素
        System.out.println("\n===anyMatch==");
        boolean b2 = emps.stream().anyMatch((e) -> e.getStatus().equals(Status.FREE));
        System.out.println(b2);

        //3、匹配-noneMatch,是否没有匹配所有元素
        System.out.println("\n===noneMatch==");
        boolean b3 = emps.stream().noneMatch((e) -> e.getStatus().equals(Status.ORTHER));
        System.out.println(b3);

        //4、返回第一个元素-findFirst(),返回Optional一个容器类,以避免数据为空的情况,使用get()获取返回的值
        System.out.println("\n===findFirst==");
        Optional<Employee> op1 = emps.stream().findFirst();
        System.out.println(op1.get());

        //orElse用于当查询内容为时,默认返回指定 对象数据
        System.out.println("\n===orElse==");
        Employee em1 = emps.stream().filter((e) -> {
            return e.getStatus().equals(Status.ORTHER);
        }).findFirst().orElse(new Employee("田七", 37, 9000, Status.ORTHER));
        System.out.println(em1);

        //5、返回流中任意一个元素-findAny,使用并行流parallelStream()演示效果,让每次拿到的数据不一样
        System.out.println("\n===findAny==");
        Optional<Employee> op2 = emps.parallelStream().filter((e) -> {
            return e.getStatus().equals(Status.FREE);
        }).findAny();
        System.out.println(op2.get());

        //6、返回数量-count(),返回流元素的数量
        System.out.println("\n===count==");
        Long count = emps.stream().count();
        System.out.println(count);

        //7、返回流中的最大值-max()
        System.out.println("\n===max==");
        Optional<Employee> op3 = emps.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(op3.get());

        //7、返回流中的最小值-min(),实例获取最低工资数值
        System.out.println("\n===min==");
        Optional<Double> op4 = emps.stream().map(Employee::getSalary).min(Double::compare);
        System.out.println(op4.get());

        //8、规约-reduce,将流中元素反复结合起来,得到一个新值
        System.out.println("\n===reduce==");
        List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = list1.stream().reduce(0, (x, y) -> x + y);
        System.out.println(sum);

        //reduce另一中方式,因为没有起始值,就可能会发回空,需要Optional类型接收
        System.out.println("\n===reduce另一中方式==");
        Optional<Double> op5 = emps.stream().map(Employee::getSalary).reduce(Double::sum);
        System.out.println(op5.get());

        //9、收集-collect,将流转为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总
        System.out.println("\n===collect==");
        List<String> list2 =  emps.stream().map(Employee::getName).collect(Collectors.toList());
        System.out.println(list2);

        //collect获取平均值
        System.out.println("\n===collect获取平均值==");
        double agv = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(agv);

        //collect获取工资总和
        System.out.println("\n===collect获取工资总和==");
        double salarySum = emps.stream().collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(salarySum);

        //collect分组
        System.out.println("\n===collect分组==");
        Map<Status, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);

        //collect连接字符串
        System.out.println("\n===collect连接==");
        String str = emps.stream().map(Employee::getName).collect(Collectors.joining(","));
        System.out.println(str);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值