JDK8新特性-stream常用API

JDK8新特性-stream常用API,第1张

JDK8新特性-stream常用API

链接: stream.
链接: 浅谈 jdk 中的 Stream 流使用及原理.
链接: stream流排序.
链接: Java 8 Steam API map和flatMap方法使用详解.

前提了解

lambda表达式、链式编程、函数式接口

函数式接口:只有一个方法的接口
  1. Function函数式接口 传入参数T 返回参数R
  2. 断定型接口:有一个输入参数,返回值只能是 布尔值
  3. Consumer 消费型接口 只有输入 没有返回值
  4. Supplier 供给型接口 没用输入,只有返回值
为什么要使用stream
  • 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 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();

    }

}
常用API list过滤
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(类似类型转换)

List collect = list.stream()
    .map(User::getUserId).collect(Collectors.toList());
System.out.println(collect);
flatMap(T -> Stream)

使用 flatMap() 将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流

多重集合 嵌套时有妙用

 //创建城市
        List> 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()

使用 distinct() 方法可以去除重复的数据

 List cityList = new ArrayList();
        cityList.add("福州");
        cityList.add("宁德");
        cityList.add("宁德");
        List collect = cityList.stream().distinct().collect(Collectors.toList());
        System.out.println(collect);

limit(long n) 和 skip(long n)

limit(long n) 方法用于返回前n条数据,skip(long n) 方法用于跳过前n条数据

List collect = list.stream().limit(1).collect(Collectors.toList());
System.out.println(collect);
anyMatch(T -> boolean)

使用 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)

空值处理
List collect = 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()));//先以属性一升序,再进行属性二降序


  1. Comparator.comparing(类::属性一).reversed(); 得到排序结果后再排序
  2. Comparator.comparing(类::属性一,Comparator.reverseOrder()); 直接进行排序

很多人会混淆导致理解出错,2更好理解,建议使用2

集合转换 list转list
list = 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());
未完持续更新中~

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5685626.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存