Java8的Steam流常用方法和总结

Stream是什么

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

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

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

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。
    这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。
    Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

在 Java 8 中, 集合接口有两个方法来生成流:

  • stream() − 为集合创建串行流。

  • parallelStream() − 为集合创建并行流。

    想要了解跟多并行流的相关内容,可参考:

    https://blog.csdn.net/sunjin9418/article/details/53143588

常用方法举例

Stream的使用可极大的减少sql的复杂度和对数据库的访问压力,我们可以用sql将数据一次性全部取出来,根据我们的实际需要,去组织我们需要的数据。

分组

// 按照sn分组:  List<Map<String, Object>> dataList
Map<String, List<Map<String, Object>>> dataMap = dataList.stream().collect(Collectors.groupingBy(e -> e.get("sn") + ""));	
//按照职员部分分组: List<Employee> list
Map<String, List<Employee>> collect = list.stream().collect(Collectors.groupingBy(i -> i.getUnitName()));
//多条件分组
Map<String, Map<String,List<Employee>>> collect =list.stream().collect(Collectors.groupingBy(i -> i.getUnitName(),Collectors.groupingBy(i -> i.getWorkType())));

过滤

//根据指定sn,过滤出符合的数据: List<Map<String, Object>> deviceDataList
List<Map<String, Object>> tempDeviceDataList = deviceDataList.stream().filter(map -> map.get("sn").toString().equals(sn)).collect(Collectors.toList());
//筛选出工资大于10000的职员
List<Employee> newList = list.stream().filter(item -> {
			return item.getSalary().compareTo(new BigDecimal(10000)) > 0 && !item.getWorkType().equals("项目经理");
		}).collect(Collectors.toList());

List和Map互转

list转map

// (k1,k2)->k2 避免键重复 k1-取第一个数据;k2-取最后一条数据
//key和value,都可以根据传入的值返回不同的Map
Map<String, String> deviceMap = hecmEnergyDevicesList.stream().collect(Collectors.toMap(i -> i.getDeviceNum(), j -> j.getDeviceName(), (k1, k2) -> k1));
//
Map<String, Object> map = list.stream()
				.collect(Collectors.toMap(i -> i.getEmpName() + i.getUnitName(), j -> j, (k1, k2) -> k1));

map转list

//在.map里面构造数据 return什么数据就转成什么类型的list
List<Employee> collect = map.entrySet().stream().map(item -> {
			Employee employee = new Employee();
			employee.setId(item.getKey());
			employee.setEmpName(item.getValue());
			return employee;
		}).collect(Collectors.toList());

求和/极值

//在egyList里面求cols的和
public static BigDecimal getSumBig(List<Map<String,Object>> egyList, String cols){
        BigDecimal consuBig = egyList.stream()
                .filter((Map m)->StringUtils.isNotEmpty(m.get(cols)+"") && !"null".equals(String.valueOf(m.get(cols)))
                        && !"-".equals(String.valueOf(m.get(cols))))
                .map((Map m)->new BigDecimal(m.get(cols)+""))
                .reduce(BigDecimal.ZERO,BigDecimal::add);
        return consuBig;
}
//List<Employee> list
//Bigdecimal求和/极值: 
BigDecimal sum = list.stream().map(Employee::getSalary).reduce(BigDecimal.ZERO,BigDecimal::add);
BigDecimal max = list.stream().map(Employee::getSalary).reduce(BigDecimal.ZERO,BigDecimal::max);
//基本数据类型求和/极值:
Integer sum = list.stream().mapToInt(Employee::getId).sum();
OptionalInt optionalMax = list.stream().mapToInt(Employee::getId).max();
optionalMax.getAsInt();

求最大/最小值的对象

Optional<Employee> optional = list.stream().collect(Collectors.maxBy(Comparator.comparing(Employee::getId)));
 if (optional.isPresent()) { // 判断是否有值
 		Employee user = optional.get();
 }
return optional.orElse(new Employee());

去重

//去重之后进行拼接: List<String> deviceNodeList
Srting deviceNodeStr = deviceNodeList.stream().distinct().collect(Collectors.joining("','"));
//直接去重返回list
// List<String> deviceIdList
 List<String> deviceIdList = deviceIdList.stream().distinct().collect(Collectors.toList());

排序

//按照时间排序 1升 -1降
Collections.sort(listFast, (p1, p2) -> {
     return String.valueOf(p1.get("time")).compareTo(p2.get("time") + "");
});
// s1-s2 升序   s2-s1降序
Collections.sort(list,(s1,s2) -> s1.getSalary().compareTo(s2.getSalary()));
//多条件排序: List<Employee> list, s1-s2 升序   s2-s1降序
list.sort(Comparator.comparing(Employee::getSalary).reversed().thenComparing(Employee::getId).reversed());

拼接

//将某个字段,按照某个字符串拼接:  List<Map<String, Object>> deviceMapList 
String sns = deviceMapList.stream()
     	.map((m)->m.get("sn")+"").collect(Collectors.joining(","));
//使用场景很多,在sql里面用于组织in的值.比如:
SELECT sn,time,value FROM electric_real_time WHERE FIND_IN_SET(sn,?)
List<Map<String, Object>> dataList = JdbcUtil.getJdbcTemplate().queryForList(dataSql, sns)

统计

//统计:和、数量、最大值、最小值、平均值: List<Employee> list
IntSummaryStatistics collect = list.stream().collect(Collectors.summarizingInt(Employee::getId));
System.out.println("和:" + collect.getSum());
System.out.println("数量:" + collect.getCount());
System.out.println("最大值:" + collect.getMax());
System.out.println("最小值:" + collect.getMin());
System.out.println("平均值:" + collect.getAverage());

平均值

OptionalDouble average = list.stream().mapToInt(Employee::getId).average();
average.getAsDouble();

某个值的数量

//List<Employee> list
Map<BigDecimal, Long> collect = list.stream().collect(Collectors.groupingBy(i -> i.getSalary(),Collectors.counting()));
//List<Map<String,Object>> egyList
long count = egyList.stream()
     .filter((Map m)->StringUtils.isNotEmpty(m.get(cols)+""))
     .map((Map m)->new BigDecimal(m.get(cols)+""))
     .count();

分区

//List<Employee> list
//单层分区
Map<Boolean, List<Employee>> collect = list.stream().collect(Collectors.partitioningBy(i -> i.getId() == 1));
//多层分区
Map<Boolean, Map<Boolean,List<Employee>>> collect = list.stream().collect(Collectors.partitioningBy(i -> i.getId() == 1,Collectors.partitioningBy(i -> i.getSalary().compareTo(new BigDecimal(20000)) == 0)));

stream流的步骤详解

Stream使用需要了解的知识点

有状态操作和无状态操作

比如map或者filter会从输入流中获取每一个元素,并且在输出流中得到一个结果,这些操作没有内部状态,称为无状态操作

但是像reduce、sum、max这些操作都需要内部状态来累计计算结果,所以称为有状态操作

还有一些操作sort、distinct,看上去和filter、map差不多,他们接收一个流,再生成一个流,但是区别在于排序和去重复项需要知道先前的历史。比如排序就需要将所有元素放入缓存区后才能给输出流加入一个项目,这个操作对缓存的要求是无上限的,流有多大就需要多大的缓存才能进行运算。这些操作也是有状态操作

中间操作和终端操作
操作类型返回值使用的函数接口或者类型
filter中间操作StreamPredicate
distinct中间操作,有状态,无边界Stream
skip中间操作,有状态,有边界Streamlong
limit中间操作,有状态,有边界Streamlong
map中间操作StreamFunction<T, R>
flatMap中间操作StreamFunction<T, Stream>
sorted中间操作,有状态,无边界StreamComparator
anyMatch终端操作booleanPredicate
noneMatch终端操作booleanPredicate
allMatch终端操作booleanPredicate
findAny终端操作Optional
findFirst终端操作Optional
forEach终端操作voidConsumer
collect终端操作RCollector<T, A, R>
reduce终端操作,有状态,有边界OptionalBinaryOperator
count终端操作long

参考文章:

https://blog.csdn.net/cc_1209/article/details/93889076

https://blog.csdn.net/sunjin9418/article/details/53086565

  • 21
    点赞
  • 173
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值