链接: stream.
链接: 浅谈 jdk 中的 Stream 流使用及原理.
链接: stream流排序.
链接: Java 8 Steam API map和flatMap方法使用详解.
lambda表达式、链式编程、函数式接口
函数式接口:只有一个方法的接口- Function函数式接口 传入参数T 返回参数R
- 断定型接口:有一个输入参数,返回值只能是 布尔值
- Consumer 消费型接口 只有输入 没有返回值
- Supplier 供给型接口 没用输入,只有返回值
- Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合 *** 作(aggregate operation),或者大批量数据 *** 作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚 *** 作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。
- 能大大减轻数据库的压力,数据库专注于存储,计算交由程序处理
简单解释一下表格中加粗字体的含义:
- 中间 *** 作:从字面上看是流从开始到结束中间的一环,从 *** 作结果上看是上一个流经过中间 *** 作生成了下一个流,从代码上看实际上是生成了一个个 stage 和 sink节点,至于 sink 节点是什么,后面的篇幅会分析
- 结束 *** 作:和中间 *** 作相反,结束 *** 作之后是流的最后一个环节,不再生成新的流,从代码上看是启动整个 sink 节点从头开始运行
- 有状态:简单理解就是需要获取流中所有数据之后才能进行的 *** 作,比如 sort 排序,肯定要获取了所有的元素之后才能排序
- 无状态:不需要获取所有元素,只需要对单个元素进行的 *** 作,比如 filter 过滤,只针对每一个元素本身所做的 *** 作
- 短路:终结 *** 作中只要有一个元素可以得到 *** 作结果的数据,比如 findAnyMatch,只要有一个节点满足筛选条件就会返回 true
- 非短路:需要遍历所有的节点才能得到预期结果,比如 forEach、max
import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; public class Test { public static List常用API list过滤init() { List userList = new ArrayList (); userList.add(new User(1, "小a", "男", 32, BigDecimal.valueOf(1600))); userList.add(new User(2, "小b", "男", 30, BigDecimal.valueOf(1800))); userList.add(new User(3, "小c", "女", 20, BigDecimal.valueOf(1700))); userList.add(new User(4, "小d", "男", 38, BigDecimal.valueOf(1500))); userList.add(new User(5, "小e", "女", 25, BigDecimal.valueOf(1200))); return userList; } public static void main(String[] args) { List list = Test.init(); } }
list.removeIf(o -> "小a".equals(o.getName()));forEach()
list.forEach(System.out::println);filter(T -> boolean) 过滤列表数据
list.stream().filter(o -> o.getUserId()!=null && o.getUserId() == 1) .collect(Collectors.toList());findAny() 和 findFirst() 获取第一条数据
搭配 filter *** 作可实现 selectOne()
注意: 建议使用主键id查找,findFirst() 和 findAny() 都是获取列表中的第一条数据,但是findAny() *** 作,返回的元素是不确定的,对于同一个列表多次调用findAny()有可能会返回不同的值。使用findAny()是为了更高效的性能。如果是数据较少,串行地情况下,一般会返回第一个结果,如果是并行(parallelStream并行流)的情况,那就不能确保是第一个。
User user = list.stream() .findFirst().orElse(null); System.out.println(user); User user1 = list.stream() .filter(o -> o.getUserId() != null && o.getUserId() == 5) .findAny().orElse(null); System.out.println(user1);map(T -> R)
使用 map() 将流中的每一个元素 T 映射为 R(类似类型转换)
ListflatMap(T -> Stream)collect = list.stream() .map(User::getUserId).collect(Collectors.toList()); System.out.println(collect);
使用 flatMap() 将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流
多重集合 嵌套时有妙用
//创建城市 Listdistinct()> cityList = new ArrayList<>(); List
cityList1 = new ArrayList (); cityList1.add("福州"); cityList1.add("宁德"); List cityList2 = new ArrayList (); cityList2.add("深圳"); cityList2.add("广州"); cityList.add(cityList1); cityList.add(cityList2); List collect = cityList.stream() .flatMap(it -> it.stream()) .collect(Collectors.toList()); System.out.println(collect);
使用 distinct() 方法可以去除重复的数据
Listlimit(long n) 和 skip(long n)cityList = new ArrayList (); cityList.add("福州"); cityList.add("宁德"); cityList.add("宁德"); List collect = cityList.stream().distinct().collect(Collectors.toList()); System.out.println(collect);
limit(long n) 方法用于返回前n条数据,skip(long n) 方法用于跳过前n条数据
ListanyMatch(T -> boolean)collect = list.stream().limit(1).collect(Collectors.toList()); System.out.println(collect);
使用 anyMatch(T -> boolean) 判断流中是否有一个元素匹配给定的 T -> boolean 条件。
boolean b = list.stream().anyMatch(o -> o.getUserId().equals(1)); System.out.println(b);allMatch(T -> boolean)
使用 allMatch(T -> boolean) 判断流中是否所有元素都匹配给定的 T -> boolean 条件。
boolean b = list.stream().allMatch(o -> o.getUserId().equals(1)); System.out.println(b);noneMatch(T -> boolean)
使用 noneMatch(T -> boolean) 流中是否没有元素匹配给定的 T -> boolean 条件。
boolean b = list.stream() .filter(o -> o!=null && o.getUserId()!=null) .noneMatch(o -> o.getUserId().equals(10)); System.out.println(b);reduce 用于组合流中的元素,如求和,求积,求最大值等
mapToInt(T -> int) 、
mapToDouble(T -> double) 、
mapToLong(T -> long)
//用户列表中年龄的最大值、最小值、总和 注意空值处理 int maxVal = list.stream().map(User::getAge).filter(Objects::nonNull).reduce(Integer::max).get(); int minVal = list.stream().map(User::getAge).filter(Objects::nonNull).reduce(Integer::min).get(); int sumVal = list.stream().map(User::getAge).filter(Objects::nonNull).reduce(0,Integer::sum); System.out.println(maxVal); System.out.println(minVal); System.out.println(sumVal);使用 count() 可以对列表数据进行统计
long count = list.stream().filter(o -> { String gender = Optional.ofNullable(o) .map(User::getGender) .orElse(""); return "男".equals(gender); } ).count(); System.out.println(count);averagingInt()、averagingLong()、averagingDouble()
double aveAge = list.stream().collect(Collectors.averagingDouble(User::getAge)); System.out.println(aveAge);summarizingInt()、summarizingLong()、summarizingDouble()
IntSummaryStatistics类提供了用于计算的平均值、总数、最大值、最小值、总和等方法
//获取IntSummaryStatistics对象 IntSummaryStatistics ageStatistics = list.stream().collect(Collectors.summarizingInt(User::getAge)); //统计:最大值、最小值、总和、平均值、总数 System.out.println("最大年龄:" + ageStatistics.getMax()); System.out.println("最小年龄:" + ageStatistics.getMin()); System.out.println("年龄总和:" + ageStatistics.getSum()); System.out.println("平均年龄:" + ageStatistics.getAverage()); System.out.println("员工总数:" + ageStatistics.getCount());BigDecimal类型的统计
reduce是一个终结 *** 作,它能够通过某一个方法,对元素进行削减 *** 作。 该 *** 作的结果会放在一个Optional变量里返回。 可以利用它来实现很多聚合方法比如count,max,min等。 T reduce(T identity, BinaryOperator accumulator); 第一个参数是我们给出的初值,第二个参数是累加器,可以自己用实现接口完 成想要的 *** 作,这里使用Bigdecimal的add方法 最后reduce会返回计算后的结果
BigDecimal result2 = list.stream().map(User::getAnnualIncome) .filter(Objects::nonNull).reduce(BigDecimal.ZERO,BigDecimal::add); System.out.println(result2);排序方法
sorted() / sorted((T, T) -> int)
空值处理Listcollect = list.stream() .sorted(Comparator.comparing(CczgResult::getName2) .thenComparing(CczgResult::getName4, Comparator.nullsFirst(String::compareTo)) .thenComparing(CczgResult::getName6, Comparator.nullsFirst(String::compareTo)) ).collect(Collectors.toList());
// 对象集合以类属性一升序排序 list.stream().sorted(Comparator.comparing(类::属性一)); // 对象集合以类属性一降序排序 注意两种写法 list.stream().sorted(Comparator.comparing(类::属性一).reversed());//先以属性一升序,结果进行属性一降序 list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()));//以属性一降序 // 对象集合以类属性一升序 属性二升序 list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二)); // 对象集合以类属性一降序 属性二升序 注意两种写法 list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二));//先以属性一升序,升序结果进行属性一降序,再进行属性二升序 list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二));//先以属性一降序,再进行属性二升序 // 对象集合以类属性一降序 属性二降序 注意两种写法 list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,升序结果进行属性一降序,再进行属性二降序 list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一降序,再进行属性二降序 // 对象集合以类属性一升序 属性二降序 注意两种写法 list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二).reversed());//先以属性一升序,升序结果进行属性一降序,再进行属性二升序,结果进行属性一降序属性二降序 list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,再进行属性二降序
- Comparator.comparing(类::属性一).reversed(); 得到排序结果后再排序
- Comparator.comparing(类::属性一,Comparator.reverseOrder()); 直接进行排序
很多人会混淆导致理解出错,2更好理解,建议使用2
集合转换 list转listlist = list.stream().map(o-> { VipInfoSear vipInfoSear = new VipInfoSear(); vipInfoSear.setId(o.getId()); return vipInfoSear; }).collect(Collectors.toList());List转map
// 一对多转换 Map分组 分组 注意空值处理> userMapGroupByGender = list.stream().collect( Collectors.groupingBy(User::getGender)); // 一对一转换 Map userMapGroupByUserId = list.stream().collect( Collectors.toMap(User::getUserId, o -> o)); // 一对一属性转换 Map map = list.stream().collect( Collectors.toMap(User::getUserId, User::getName));
lisrt.stream() .filter(t-> StringUtils.isNotBlank(t.getName12())) .collect(Collectors.groupingBy(CczgResult::getName12));分组多条件统计
Map未完持续更新中~countMap = records.stream().collect(Collectors.groupingBy(o -> o.getProductType() + "_" + o.getCountry(), Collectors.counting())); List countRecords = countMap.keySet().stream().map(key -> { String[] temp = key.split("_"); String productType = temp[0]; String country = temp[1]; Record record = new Record(); record.set("device_type", productType); record.set("location", country; record.set("count", countMap.get(key).intValue()); return record; }).collect(Collectors.toList());
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)