文章目录
- 概念和特点
- 基本流程
- 常见操作
- 过滤(filter)
- 映射(map)
- 收集(collect)
- 归约(reduce)
- 扁平映射(flatMap)
- java案例详解
- 注意事项
概念和特点
Java中的Stream是用于处理集合数据的功能强大且灵活的API。Stream 是 Java 8 引入的一个新特性,它允许以函数式编程的方式来处理集合数据。通过使用 Stream可以写出更简洁、意图明确的代码,并且可以利用多核处理器的优势来并行处理数据,提高程序性能。
基本流程
- 首先需要将集合转换为 Stream, 可以从很多种数据源中创建Stream,例如List、Set或者任何其他实现了Iterable接口的类。创建方式很简单,使用stream()或parallelStream()方法即可。
- 然后通过中间操作对 Stream 进行一系列的处理。常用的Stream操作包括:过滤、映射、排序、去重、计数、归约等等。
- 最终通过终止操作得到处理结果。
常见操作
常用的Stream操作包括:过滤、映射、排序、去重、计数、归约等等。
过滤(filter)
根据条件筛选出符合条件的元素,过滤方法filter用于对Stream中的元素进行筛选,只保留符合指定条件的元素。其函数式接口为Predicate,其方法为boolean test(T t),接受一个T类型的对象,并返回一个boolean类型值。当该方法返回true时,说明该元素符合条件,将被保留在Stream中.
映射(map)
将 Stream 中的每个元素转换成另一种形式。映射方法map用于将Stream中的元素根据指定规则进行转换。其函数式接口为Function<T, R>,其方法为R apply(T t),接受一个T类型的对象,并返回一个R类型的对象。实质上,map方法就是对Stream中各元素做一个同类型的映射
收集(collect)
将 Stream 中的元素收集到如 List、Set 或 Map 等集合中。
归约(reduce)
将 Stream 中的元素组合起来生成一个值。
扁平映射(flatMap)
将 Stream 中的每个元素转换为另一个 Stream,然后合并为一个 Stream。
java案例详解
package cn.hyperchain.liststream;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @author zhu
* @Date 2022/1/7 11:14 AM
* JAVA8 新特性:stream流操作集合
* 案例:查询集合中age<20的学生,并且根据年龄进行排序,得到学生的姓名,生成新的集合
*/
//@SpringBootTest
public class ListStreamTest {
private static List<Student> students = null;
static {
students = new ArrayList<>();
students.add(new Student(1, "张三", "M", 19));
students.add(new Student(2, "李四", "M", 18));
students.add(new Student(3, "王武", "F", 21));
students.add(new Student(4, "赵六", "F", 20));
students.add(new Student(1, "张三", "M", 19));
students.add(new Student(2, "李四", "M", 18));
students.add(new Student(3, "王武", "F", 21));
students.add(new Student(4, "赵六", "F", 20));
}
/**
* 0. List stream流基本操作
*/
@Test
public void testStream() {
// 案例一:
List<String> res = students.stream()
.filter(student -> student.getAge() < 20) // 集合中age<20
.distinct() // 对象去重
.sorted(Comparator.comparing(Student::getAge)) // 根据年龄进行排序
.map(Student::getName) // 得到学生的姓名[可以有多个字段,但是需要封装]
.collect(Collectors.toList()); // 生成新的集合
System.out.println("res = " + res);
// 案例二:
List<Integer> list = Arrays.asList(1, 1, 3, 43, 12, 43, 32, 1, 42, 3, 32, 43);
List<Integer> result = list.stream() // 1, 1, 3, 43, 12, 43, 32, 1, 42, 3, 32, 43
.distinct() // 去重 1,3,43,12,32,42
.limit(5) // 集合大小为5 1,3,43,12,32
.skip(2) // 跳过前2个元素 43,12,32
.collect(Collectors.toList());
System.out.println("result = " + result);
}
/**
* 1. List stream流快速取集合元素某一个属性或多个属性,并转为List、Map、Set
*/
@Test
public void testMap() {
// 1. List快速取一个字段为List
List<Integer> ids = students.stream().map(Student::getId).collect(Collectors.toList());
ids.forEach(System.out::println);
// 2. List快速取多个字段组成一个Entity为List
List<StudentDTO> dtos = students.stream()
.map(new Function<Student, StudentDTO>() { // 封装students的某些属性,函数式编程,Function已声明为@FunctionalInterface,此时作为参数传递,主要进行类型转换
@Override
public StudentDTO apply(Student student) {
return StudentDTO.builder()
.id(student.getId())
.name(student.getName())
.build();
}
})
.collect(Collectors.toList());
System.out.println("dtos = " + dtos);
// 3. List快速取Map
Map<Integer, Student> map = students.stream().collect(Collectors.toMap(Student::getId, Function.identity())); // Function.identity() 表示直接返回对应的 DeviceExtendDto 对象作为 Value
// 4. List快速取Set:值不可重复,List值可重复
Set<Integer> set = students.stream().map(Student::getId).collect(Collectors.toSet());
System.out.println("set = " + set);
// 5. 分组为Map
// Map<AttrTypeEnum, List<T2>> attrMap = attrs.stream().filter(t -> AttrTypeEnum.DEVICE != t.getType()).collect(Collectors.groupingBy(T2::getType));
}
/**
* 2. List stream流快速判断Predicate
*/
@Test
public void testMatch() {
// 写法一:testAnyMatch[判断集合任一个元素满足要求]
boolean b1 = students.stream()
.distinct()
.anyMatch(new Predicate<Student>() { // 匹配 anyMatch
@Override
public boolean test(Student student) {
return student.getName().equals("张三");
}
});
System.out.println("b1 = " + b1);
// 写法二:testAnyMatch
boolean b2 = students.stream()
.distinct()
.anyMatch(student -> student.getName().equals("张三"));
System.out.println("b2 = " + b2);
}
@Test
public void testFind() {
Optional<Student> studentOptional = students.stream()
.distinct()
// .findAny(); // 随机获取一个元素
.findFirst(); // 获取第一个元素
if (studentOptional.isPresent()) {
Student student = studentOptional.get();
System.out.println("student = " + student);
}
}
}
注意事项
Stream 不会自己存储元素,也不会改变源对象。它会返回一个新的 Stream,这个新的 Stream 持有之前所有操作的结果。
Stream 的操作是延迟执行的,只有在真正需要结果的时候才会执行这些操作。