目录
一、导言
二、什么是流式编程(Stream流)
三、Stream流的工作图
四、Stream流中常见的api
一、获取Stream流对象的方式
二、Stream流中间操作
1.过滤(filter):对Stream流中的数据进行过滤
2.映射(map):对Stream流中的数据进行转换
3.映射(flatMap):对Stream流中的数据作扁平化处理
4.排序(sort):对Stream流中的数据做排序
5.去重(distinct):对Stream流中的数据做去重操作
6.截取(limit):用于截取流中的元素
三、Stream流终止操作
1.收集(collect):用于将流中的元素收集到一个集合或者其他容器中
2.规约(reduce):用于将流中的元素进行规约操作,它接收一个BinaryOperator参数,用于定义规约的逻辑
3.循环(forEach):用来遍历流中的数据
4.计数(count):统计流中元素个数
5.查找(find):获取满足条件的第一个元素
6.匹配(match):判断流中元素是否满足条件,返回值为Boolean类型
7.最值(max,min)
五、实际应用案例
简要介绍Java 8中引入的流式编程特性。强调流式编程在简化代码、提高性能和增强可读性方面的重要性。提及本文将深入探讨流式编程的定义、基本操作、中间操作、终端操作以及实际应用案例。
流式编程(Stream流)是一种在计算机编程中用于处理数据集合的新型方法。它在Java 8中被引入,并在之后的版本中得到了扩展和优化。流式编程的核心思想是以一种类似于流水线的方式来处理数据,通过一系列的操作来对数据进行筛选、转换、合并和归约,从而实现更简洁、更高效、更可读的代码编写。
// 通过集合类的stream()方法
List list = Arrays.asList("a", "b", "c");
Stream stream = list.stream();
// 通过Arrays类的stream()方法
String[] array = {"a", "b", "c"};
Stream stream = Arrays.stream(array);
// 通过Stream类的of()方法
Stream stream = Stream.of("a", "b", "c");
// 通过Stream类的builder()方法
Stream.Builder builder = Stream.builder();
builder.add("a").add("b").add("c");
Stream stream = builder.build();
public static void main(String[] args) {
// 构建数据源
Person person1 = new Chinese("大白", 25, Sex.woman);
Person person2 = new Chinese("小赵", 28, Sex.man);
Person person3 = new Chinese("小明", 20, Sex.man);
Person person4 = new Chinese("小兰", 17, Sex.woman);
Person person5 = new Chinese("小赵", 18, Sex.man);
Person person6 = new Chinese("小马", 50, Sex.man);
List peopleList = Arrays.asList(person1, person2, person3, person4, person5, person6);
// 需求:筛选出年龄大于25的学生信息
peopleList.stream() // 获取流对象
.filter(person -> person.getAge() > 25)// 筛选出年龄大于25的学生信息
.forEach(System.out::println); // 打印输出满足条件的对象信息
}
public class StreamMap {
public static void main(String[] args) {
// 构建数据源
Person person1 = new Chinese("大白", 25, Sex.woman);
Person person2 = new Chinese("小赵", 28, Sex.man);
Person person3 = new Chinese("小明", 20, Sex.man);
Person person4 = new Chinese("小兰", 17, Sex.woman);
Person person5 = new Chinese("小赵", 18, Sex.man);
Person person6 = new Chinese("小马", 50, Sex.man);
List peopleList = Arrays.asList(person1, person2, person3, person4, person5, person6);
// 需求:获取所有对象的姓名
peopleList.stream() // 获取流对象
.map(person -> person.getName()) // 将Person类型 --> String类型
.forEach(System.out::println); // 打印输出所有对象姓名
}
}
// Grades类的定义如下:
public class Grades {
// 班级名称
public String className;
public List personList;
}
public class FlatMapTest {
public static void main(String[] args) {
// 构建数据源
List classList = new ArrayList<>();
Person person = new Chinese("小明", 25, Sex.man);
Person person1 = new Chinese("小红", 23, Sex.woman);
Person person2 = new Chinese("小白", 22, Sex.man);
Person person3 = new Chinese("小黑", 20, Sex.man);
Person person4 = new Chinese("小兰", 29, Sex.woman);
Person person5 = new Chinese("小李", 18, Sex.man);
Person person6 = new Chinese("小黄", 50, Sex.man);
Person person7 = new Chinese("小青", 29, Sex.woman);
Person person8 = new Chinese("小倩", 18, Sex.man);
Person person9 = new Chinese("小灰", 50, Sex.man);
// 班级1的学生信息
Grades class1 = new Grades("class1", Arrays.asList(person, person1, person2, person3));
// 班级2的学生信息
Grades class2 = new Grades("class2", Arrays.asList(person4, person5, person6));
// 班级3的学生信息
Grades class3 = new Grades("class3", Arrays.asList(person7, person8, person9));
classList.add(class1);
classList.add(class2);
classList.add(class3);
// 需求:获取所有班级的学生信息,并打印输出
classList.stream() // 获取流对象
.flatMap(x->x.getPersonList().stream()) // 对Grades对象中的personList做扁平化处理
.forEach(System.out::println); // 打印展示所有班级学生信息
}
}
public class StreamSortBy {
public static void main(String[] args) {
// 构建数据源
Person person1 = new Chinese("大白", 25, Sex.woman);
Person person2 = new Chinese("小赵", 28, Sex.man);
Person person3 = new Chinese("小明", 20, Sex.man);
Person person4 = new Chinese("小兰", 17, Sex.woman);
Person person5 = new Chinese("小赵", 18, Sex.man);
Person person6 = new Chinese("小马", 50, Sex.man);
List peopleList = Arrays.asList(person1, person2, person3, person4, person5, person6);
// 需求:按照年龄升序排序
peopleList.stream() // 获取流对象
.sorted(Comparator.comparing(Person::getAge)) //传入一个比较器,按照年龄升序排列
.forEach(System.out::println); // 打印排序后的所有学生信息
}
}
public class StreamDistinct {
public static void main(String[] args) {
// 需求:去除重复元素
Stream.of("张三", "李四", "王五", "张三", "赵六", "李四") // 获取流对象
.distinct() // 对重复元素进行去重操作
.forEach(System.out::println); // 打印去重后的元素
}
}
public class StreamLimit {
public static void main(String[] args) {
// 构建数据源
Person person1 = new Chinese("大白", 25, Sex.woman);
Person person2 = new Chinese("小赵", 28, Sex.man);
Person person3 = new Chinese("小明", 20, Sex.man);
Person person4 = new Chinese("小兰", 17, Sex.woman);
Person person5 = new Chinese("小赵", 18, Sex.man);
Person person6 = new Chinese("小马", 50, Sex.man);
List peopleList = Arrays.asList(person1, person2, person3, person4, person5, person6);
// 需求:获取年龄最小的学生信息
peopleList.stream()
.sorted(Comparator.comparingInt(Person::getAge)) // 按照年龄升序排列
.limit(1) // 获取排序后的第一个元素
.forEach(System.out::println); // 打印学生信息
}
}
@Slf4j
public class StreamCollect {
public Person[] peoples;
public List personList;
// 构建数据源
@Before
public void before() {
Person person = new Chinese("小明", 21, Sex.man);
Person person1 = new Chinese("大白", 25, Sex.woman);
Person person2 = new Chinese("小赵", 23, Sex.man);
Person person3 = new Chinese("小兰", 20, Sex.man);
Person person4 = new Chinese("小红", 18, Sex.woman);
Person person5 = new Chinese("小李", 17, Sex.man);
Person person6 = new Chinese("小麻", 50, Sex.man);
this.peoples =new Person[]{ person, person1, person2, person3, person4, person5, person6};
this.personList = Arrays.asList(peoples);
}
// 收集成List
@Test
public void collectToListTest() {
// 需求:按照年龄升序排列,并收集为集合
List persons = this.personList.stream() // 获取流对象
.sorted(Comparator.comparingInt(Person::getAge)) // 按照年龄进行排序
.collect(Collectors.toList()); //收集成集合
}
// 收集为map
@Test
public void groupBySexTest() {
// 需求: 按照性别信息分组展示学生信息
this.personList.stream() // 获取一个流对象
.collect(Collectors.groupingBy(Person::getSex)) // 按照性别进行分组操作
.forEach((key, value) -> { // 按性别分组打印学生信息
value.forEach(System.out::println);
System.out.println("================");
});
}
// 收集为map
@Test
public void groupByAndAveragingIntTest() {
// 需求:请计算全班男生的平均年龄和全班女生的平均年龄
this.personList.stream() // 获取流对象
.distinct() // 去重操作
.collect(Collectors.groupingBy(Person::getSex, Collectors.averagingInt(Person::getAge))) //按性别分组,并求年龄平均值
.forEach((sex, aLong) -> log.info("性别:{}, 年龄总和:{}", sex, aLong)); //打印信息
}
}
public class StreamReduce {
/**
* reduce()方法有两种重载形式:
*
* 1.T reduce(T identity, BinaryOperator accumulator):指定一个初始值identity,通过accumulator定义的规约逻辑,将流中的元素进行累积计算,返回规约结果。
* 2.Optional reduce(BinaryOperator accumulator):根据accumulator定义的规约逻辑,将流中的元素进行递归计算,返回Optional类型的规约结果。
*/
// 方式一
@Test
public void ReduceTest01() {
// 需求:求解集合中所有元素的和
List numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
// sum = 15
}
// 方式二
@Test
public void ReduceTest02() {
List numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional max = numbers.stream()
.reduce(Integer::max);
// max = Optional[5]
}
}
public class Stream_ForEach {
public static void main(String[] args) {
//获取一个Stream流
Streamstream= Stream.of("张三","李四","王五","赵六");
//使用Stream流的方法forEach对stream流中的数据遍历
stream.forEach(System.out::println);
}
}
public class StreamCount {
public static void main(String[] args) {
long count = Stream.of("张三", "李四", "赵六", "王五", "小七").count();
// count --> 5
}
}
public class StreamFind {
public Person[] peoples;
public List personList;
// 构建数据源
@Before
public void before() {
Person person = new Chinese("小明", 21, Sex.man);
Person person1 = new Chinese("大白", 25, Sex.woman);
Person person2 = new Chinese("小李", 23, Sex.man);
Person person3 = new Chinese("小兰", 20, Sex.man);
Person person4 = new Chinese("小红", 18, Sex.woman);
Person person5 = new Chinese("小李", 17, Sex.man);
Person person6 = new Chinese("小麻", 50, Sex.man);
this.peoples =new Person[]{ person, person1, person2, person3, person4, person5, person6};
this.personList = Arrays.asList(peoples);
}
@Test
public void findTest01() {
// 需求:查找姓名为小明的学生信息,找不到则抛出异常信息
Person result = this.personList.stream()
.filter(person -> "小明".equals(person.getName()))
.findFirst()
.orElseThrow(RuntimeException::new);
System.out.println(result);
}
}
@Slf4j
public class AnyMatchStreamTest {
public Person[] peoples;
public List personList;
@Before
public void before() {
Person person = new Chinese("小明", 22, Sex.man);
Person person1 = new Chinese("小红", 24, Sex.woman);
Person person2 = new Chinese("小李", 21, Sex.man);
Person person3 = new Chinese("小明", 21, Sex.man);
Person person4 = new Chinese("小红", 19, Sex.woman);
Person person5 = new Chinese("小李", 18, Sex.man);
Person person6 = new Chinese("小麻", 50, Sex.man);
this.peoples =new Person[]{ person, person1, person2, person3, person4, person5, person6};
this.personList = Arrays.asList(peoples);
}
@Test
public void allMatchTest() {
// 需求:判断学生年龄是否全部大于20岁
if (this.personList.stream().allMatch(person -> person.getAge() > 20)) { //流中所有元素满足条件即为true
System.out.println("学生年龄全部大于20岁");
}
}
@Test
public void anyMatchTest() {
// 需求:判断所有学生中是否有姓名为"小麻"的学生
if (this.personList.stream().anyMatch(person -> "小麻".equals(person.getName()))) { // 流中任意一个元素满足条件即为true
System.out.println("学生中有姓名为小麻的学生");
}
}
@Test
public void noneMatchTest() {
// 需求:判断所有学生中是否有姓名为"小麻"的学生
if (this.personList.stream().noneMatch(person -> "小麻".equals(person.getName()))) { //流中所有元素都不满足条件即为true
System.out.println("学生中没有姓名为小麻的学生");
}
}
}
public class StreamMaxAndMin {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(new Test("小赵",23,new BigDecimal("3000"),new BigDecimal("1.1")));
list.add(new Test("赵六",24,new BigDecimal("2800"),new BigDecimal("1.2")));
list.add(new Test("小兰",22,new BigDecimal("3200"),new BigDecimal("1.3")));
//获取年龄最大的人
Test maxPeople = list.stream().max(Comparator.companing(Test::getAge)).get();
//获取年龄最小的人
Test minPeople = list.stream().min(Comparator.companing(Test::getAge)).get();
}
}
1.sort用法示例
@Test
public void sortByAgeTest() {
// 获取年龄最大的学生信息,没找到这返回"小麻"
String name = this.personList.stream()
.max(Comparator.comparing(Person::getAge))
.orElseGet(() -> new Chinese("小麻", 23, Sex.man)).getName();
System.out.println(name);
}
2.flatMap用法示例
@Slf4j
public class FlatMapTest {
public static void main(String[] args) {
// 构建数据源
List classList = new ArrayList<>();
Person person = new Chinese("小明", 25, Sex.man);
Person person1 = new Chinese("小红", 23, Sex.woman);
Person person2 = new Chinese("小白", 22, Sex.man);
Person person3 = new Chinese("小黑", 20, Sex.man);
Person person4 = new Chinese("小兰", 29, Sex.woman);
Person person5 = new Chinese("小李", 18, Sex.man);
Person person6 = new Chinese("小黄", 50, Sex.man);
Person person7 = new Chinese("小青", 29, Sex.woman);
Person person8 = new Chinese("小倩", 18, Sex.man);
Person person9 = new Chinese("小灰", 50, Sex.man);
// 班级1的学生信息
Grades class1 = new Grades("class1", Arrays.asList(person, person1, person2, person3));
// 班级2的学生信息
Grades class2 = new Grades("class2", Arrays.asList(person4, person5, person6));
// 班级3的学生信息
Grades class3 = new Grades("class3", Arrays.asList(person7, person8, person9));
classList.add(class1);
classList.add(class2);
classList.add(class3);
// 需求:获取所有班级的学生信息,并打印输出
classList.stream() // 获取流对象
.flatMap(x->x.getPersonList().stream()) // 对Grades对象中的personList做扁平化处理
.forEach(System.out::println); // 打印展示所有班级学生信息
}
}
3.groupBy的用法示例
@Slf4j
public class GroupByStreamTest {
public Person[] peoples;
public List personList;
public List actualByBudgetSubjectOrganizationList = new ArrayList<>();
@Before
public void before() {
Person person = new Chinese("小明", 21, Sex.man);
Person person1 = new Chinese("小红", 25, Sex.woman);
Person person2 = new Chinese("小李", 23, Sex.man);
Person person3 = new Chinese("小明", 20, Sex.man);
Person person4 = new Chinese("小红", 18, Sex.woman);
Person person5 = new Chinese("小李", 17, Sex.man);
Person person6 = new Chinese("小麻", 50, Sex.man);
ActualByBudgetSubjectOrganization actualByBudgetSubjectOrganization = null;
for (int i =0; i<10; i++){
// 生成0-100之间的随机数
Random random = new Random();
long amountMoney = random.nextLong() % 101; // 生成-100到100之间的随机数
if (amountMoney < 0) {
amountMoney = -amountMoney; // 将负数转化为正数
}
if(i<5){
actualByBudgetSubjectOrganization=ActualByBudgetSubjectOrganization.builder()
.companyCode("10")
.operationNo("001")
.yearMonth("202210")
.budgetSubjectCode("PT101")
.amountMoney(amountMoney).build();
this.actualByBudgetSubjectOrganizationList.add(actualByBudgetSubjectOrganization);
continue;
}
actualByBudgetSubjectOrganization = ActualByBudgetSubjectOrganization.builder()
.companyCode("G0")
.operationNo("001")
.yearMonth("202210")
.budgetSubjectCode("PT102")
.amountMoney(amountMoney).build();
this.actualByBudgetSubjectOrganizationList.add(actualByBudgetSubjectOrganization);
}
this.peoples =new Person[]{ person, person1, person2, person3, person4, person5, person6};
this.personList = Arrays.asList(peoples);
}
// stream流的分组转换
@Test
public void groupByAgeTest() {
Map> result = this.personList.stream().collect(Collectors.groupingBy(Person::getAge));
Set keys = result.keySet();
for (Integer key : keys) {
result.get(key).stream().forEach(System.out::println);
System.out.println("================");
}
}
@Test
public void groupBySexTest() {
Map> result = this.personList.stream().collect(Collectors.groupingBy(Person::getSex));
Set keys = result.keySet();
for (Sex key : keys) {
result.get(key).stream().forEach(System.out::println);
System.out.println("================");
}
}
// stream流的分组转换
@Test
public void groupByNameTest() {
this.personList.stream()
.collect(Collectors.groupingBy(Person::getName))
.forEach((key, value) -> {
value.forEach(System.out::println);
System.out.println("================");
});
}
// 先分组在求和
@Test
public void groupByAndSummingLongTest() {
// 先分组在求和,注意Collectors.summingLong(ActualByBudgetSubjectOrganization::getAmountMoney是作为Collectors.groupingBy的一个参数
Map collect = this.actualByBudgetSubjectOrganizationList.stream()
.collect(Collectors.groupingBy(ActualByBudgetSubjectOrganization::getBudgetSubjectCode,
Collectors.summingLong(ActualByBudgetSubjectOrganization::getAmountMoney)));
Set keys = collect.keySet();
keys.forEach(key-> log.info("key:{},value:{}",key, collect.get(key)));
}
// 请计算全班男生的平均年龄和全班女生的平均年龄。
@Test
public void groupByAndAveragingIntTest() {
Map collect1 = this.personList.stream().distinct().collect(Collectors.groupingBy(Person::getSex, Collectors.averagingInt(Person::getAge)));
collect1.forEach((sex, aLong) -> log.info("性别:{}, 年龄总和:{}", sex, aLong));
boolean b = this.personList.stream().distinct().anyMatch(x -> x.getAge() > 9);
// boolean b = this.personList.stream().distinct().max();
}
}
4.peek用法示例
@Slf4j
public class PeekStreamTest {
public Person[] peoples;
public List personList;
@Before
public void before() {
Person person = new Chinese("小明", 23, Sex.man);
Person person1 = new Chinese("小红", 15, Sex.woman);
Person person2 = new Chinese("小李", 58, Sex.man);
Person person3 = new Chinese("小明", 62, Sex.man);
Person person4 = new Chinese("小红", 11, Sex.woman);
Person person5 = new Chinese("小李", 38, Sex.man);
Person person6 = new Chinese("小麻", 20, Sex.man);
this.peoples =new Person[]{ person, person1, person2, person3, person4, person5, person6};
this.personList = Arrays.asList(peoples);
}
@Test
public void peekTest01() {
List numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.peek(number -> System.out.println("Processing number: " + number)) // 打印流的执行过程
.filter(number -> number % 2 == 0)
.forEach(System.out::println);
}
// 统一将Person对象中的某一属性修改成固定值
@Test
public void peekTest02() {
// 统一将Person对象中的性别属性修改成男, 注意this.personList.stream().peek(x -> x.setSex(Sex.man))仍会返回一个stream流
this.personList.stream().peek(x -> x.setSex(Sex.man)).forEach(System.out::println);
}
}
3.first用法示例
@Test
public void firstTest() {
// 获取年龄大于50岁,并取其第一个元素
String firstElementValue = this.personList.stream()
.filter(x -> x.getAge() > 50)
.findFirst().map(Person::getName).orElseGet(() -> "");
log.info("firstElementValue--->{}", firstElementValue);
}
3.removeIf用法示例
public class RemoveIfStreamTest {
public Person[] peoples;
public List personList;
@Before
public void before() {
Person person = new Chinese("小兰", 22, Sex.man);
Person person1 = new Chinese("小赵", 24, Sex.woman);
Person person2 = new Chinese("小白", 21, Sex.man);
Person person3 = new Chinese("小黄", 21, Sex.man);
Person person4 = new Chinese("小黑", 19, Sex.woman);
Person person5 = new Chinese("小李", 18, Sex.man);
Person person6 = new Chinese("小麻", 50, Sex.man);
this.peoples =new Person[]{ person, person1, person2, person3, person4, person5, person6};
this.personList = Arrays.asList(peoples);
}
@Test
public void removeIfTest() {
List personList = new ArrayList<>(this.personList);
personList.add(null);
personList.add(null);
personList.add(null);
personList.add(null);
personList.removeAll(Collections.singletonList(null));
//personList.removeIf(Objects::isNull);
personList.removeIf(x -> x.getAge() > 30);
personList.forEach(System.out::println);
}
}