Java Stream 流的使用
在实际生产中,几乎很少使用for循环的结构进行操作,Java 8 提供的Stream可以大大提高程序员的生产力,由于自己之前对于Stream 流使用的并不是很熟练,所以在这里进行简单的总结归纳。
最后熟练的使用Stream流,不仅仅是对基础的熟悉,还是需要对于业务的一些理解需要比较深刻。
一、Stream 流的介绍
Stream流是类似于SQL语句,可以通过一种比较直观的方式对java的集合进行运算。
Stream 流,就是将要处理的元素看作是一种流,这个流在管道中运输,我们可以在管道中对管道中的节点进行处理,比如 筛选、排序、聚合 等等。
可以通过以下图,了解流的使用:
+--------------------+ +------+ +------+ +---+ +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+ +------+ +------+ +---+ +-------+
Stream流有以下特点:
- 元素是特定类型的对象,形成一个队列。Java的Stream流不会存储元素,而是按需计算。
- Stream数据流的来源,可以是集合、数组,I/O,产生器等等。
- 聚合操作包括filter, map, reduce, find, match, sorted等等。
生成流
- stream() 为集合创建串行流;目前基本都是串行流
- parallelStream() 为集合创建并行流;
二、使用方式介绍
forEach
forEach可以迭代流中的每个元素。
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
map
map用于映射每个元素对应的结果。
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter
filter可以设置过滤条件。
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();
limit
limit可以用于获取指定数量的流。
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted
sorted可以对流里面的对象进行排序
Random random = new Random();
random.ints().limit(10).sorted((x,y) -> x.getWeight() - y.getWeight()).forEach(System.out::println);
Collectors
Collectors实现了很多归约操作,可以将流对象转换成集合,hash表(Map)、set、List等等
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
三、实战举例
1. 创建实体类
public class Organization {
/**
* 自增主键
*/
private Long id;
/**
* 组织id
*/
private Long orgId;
/**
* 组织名称
*/
private String orgName;
/**
* 组织简称
*/
private String simpleName;
/**
* 组织标签
*/
private String labels;
/**
* 组织行业
*/
private String industry;
/**
* 状态,1为删除,0为正常
*/
private Integer status;
/**
* 创建时间
*/
private Long createTime;
/**
* 更新时间
*/
private Long updateTime;
}
2. 创建流
Stream流有两种类型,串行流,大部分基本都是串行流,小部分是并行流。
List<Organization> organizationList = new ArrayList<>();
//1. 创建一个串行stream对象
Stream<Organization> stream = organizationList.stream();
//2. 创建一个并行stream对象
Stream<Organization> parallelStream = organizationList.parallelStream();
3. filter
filter 主要是做筛选, filter括号里面结果满足返回true 不满足返回false,返回结果为return true筛选后的结果
//filter 过滤
organizationList = organizationList.stream().filter(organization -> organization.getId() > 5).collect(Collectors.toList());
//以下是等价的:
organizationList = organizationList.stream().filter(organization -> {
if (organization.getId() > 5) {
return true;
} else {
return false;
}
}).collect(Collectors.toList());
4. forEach
forEach主要用来遍历
//forEach 遍历
organizationList.stream().forEach(System.out::println);
5. map
map可以对里面的对象进行操作,设置元素值,也可以获取对象里面的特定属性,转换为一个集合。
(1)获取自己想要的值
//获取industry属性,并将其转换为list
List<String> industryList = organizationList.stream()
.map(organization -> organization.getIndustry())
.collect(Collectors.toList());
industryList.stream().forEach(System.out::println);
(2) 设置里面的元素的属性
// 将orgName属性设置为New Name + id
organizationList = organizationList.stream().map(organization -> {
organization.setOrgName("New Name " + organization.getId());
return organization;
}).collect(Collectors.toList());
6.controller
特别重要的,需要掌握的一点。可以将流对象转化为各种形式,比如map, list, set等等。
//collect 将流转换为其他形式,如list、set、map等
Map<Long, Organization> organizationMap = organizationList.stream()
.collect(Collectors.toMap(Organization::getId, organization -> organization));
// map中key重复用这个加(oldValue, newValue) -> oldValue 的方法,保留旧的值
organizationMap = organizationList.stream()
.collect(Collectors.toMap(Organization::getId, organization -> organization, (oldValue, newValue) -> oldValue));
// 将流转换为list
List<Long> idList = organizationList.stream().map(Organization::getId).collect(Collectors.toList());
// 将流转换为set
Set<Long> idSet = organizationList.stream().map(Organization::getId).collect(Collectors.toSet());
7.sorted
可以对流中的元素进行排序。可以正序,逆序。
//sorted 对流中的元素进行排序
organizationList = organizationList.stream().sorted((o1, o2) -> {
if (o1.getId() > o2.getId()) {
return 1;
} else {
return -1;
}
}).collect(Collectors.toList());
//根据Id进行增序排序
organizationList.stream().sorted((o1, o2) -> (int)(o1.getId() - o2.getId())).collect(Collectors.toList());
//根据Id进行降序排序
organizationList.stream().sorted((o1, o2) -> (int)(o2.getId() - o1.getId())).collect(Collectors.toList());
8. count
count可以获取到数量,进行计数
//统计流中的元素数量
long count = organizationList.stream().count();
9.limit
limit可以限制在stream流中获取的个数
//最多获取到前五个数据
organizationList = organizationList.stream().limit(5).collect(Collectors.toList());
10.skip
skip可以跳过数据的个数
//跳过第1个元素
organizationList = organizationList.stream().skip(1).collect(Collectors.toList());
四、组合复杂运算
//1.根据orgId进行分组,分组之后,再将他所属的Id组合起来,将其转换为<Map<Long, List<Long>>形式
Map<Long, List<Long>> getUserList = organizationList.stream()
.collect(Collectors.groupingBy(
Organization::getOrgId,
Collectors.mapping(
Organization::getId,
Collectors.toList()
)
));
//2.