Java8 Stream流

1.Stream流

1.1 体验Stream流

需求:按照下面的要求完成集合的创建和遍历

  • 创建一个集合,存储多个字符串元素
  • 把集合中所有以"张"开头的元素存储到一个新的集合
  • 把"张"开头的集合中的长度为3的元素存储到一个新的集合
  • 遍历上一步得到的集合使用Stream流的方式完成过滤操作
  • list.stream().filter(s -> s.startsWith(“张”)).filter(s -> s.length() ==3).forEach(System.out::println);
  • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
  • Stream流把真正的函数式编程风格引入到Java中

1.2 Stream流的思想和生成方式

Stream流的使用
  • 生成流

    ​ 通过数据源(集合,数组等)生成流list.stream()

  • 中间操作

    ​ 一个流后面可以跟随零个或多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用filter()

  • 终结操作

    ​ 一个流只能有一个终结操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作forEach

Stream流的常见生成方式
  • Collection体系的集合可以使用默认方法stream()生成流default Stream stream()
  • Map体系的集合间接的生成流
  • 数组可以通过Stream接口的静态方法of(T… values)生成流

1.3 Stream流的常见中间操作方法

Stream流的常见中间操作方法
  • Stream filter(Predicate predicate):用于对流中的数据进行过滤

    ​ Predicate接口中的方法boolean test(T t):对给定的参数进行判断,返回一个布尔值

  • Stream limit(long maxSize):返回此流中的元素组成的流,截取前指定参数个数的数据

  • Stream skip(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流

  • static Stream concat(Stream a, Stream b):合并a和b两个流为一个流

  • Stream distinct():返回由该流的不同元素(根据Object.equals(Object))组成的流

  • Stream sorted():返回由此流的元素组成的流,根据自然顺序排序

  • Stream sorted(Comparator comparator):返回由该流的元素组成的流,根据提供的Comparator进行排序

    • Stream map(Function mapper):返回由给定函数应用于此流的元素的结果组成的流

    ​ Function接口中的方法 R apply(T t)

    • IntStream mapToInt(ToIntFunction mapper):返回一个IntStream其中包含将给定函数应用于此流的元素的结果

    ​ IntStream:表示原始 int 流

    ​ ToIntFunction接口中的方法 int applyAsInt(T value)

1.4 Stream流的常见终结操作方法

Stream流的常见终结操作方法
  • void forEach(Consumer action):对此流的每个元素执行操作

​ Consumer接口中的方法 void accept(T t):对给定的参数执行此操作

  • long count():返回此流中的元素数

1.5 Stream流的收集操作

对数据使用Stream流的方式操作完毕后,我想把流中的数据收集到集合中,该怎么办呢?

Stream流的收集方法
  • R collect(Collector collector)
  • 但是这个收集方法的参数是一个CollectorCollector接口

工具类Collectors提供了具体的收集方式

  • public static Collector toList():把元素收集到List集合中
  • public static Collector toSet():把元素收集到Set集合中
  • public staticCollector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中

2.Collector

Collector是专门用来作为Stream的collect方法的参数的,而Collectors是作为生产具体Collector的工具类。

2.1Collectors收集器

2.1.1 toCollection

将流中的元素全部放置到一个集合中返回,这里使用Collection,泛指多种集合。

public void toCollectionTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    List<String> ll = list.stream().collect(Collectors.toCollection(LinkedList::new));
    System.out.println(ll);
}

// 打印结果:[123, 456, 789, 1101, 212121121, asdaa, 3e3e3e, 2321eew]
2.1.2 toList

将流中的元素放置到一个列表集合中去。这个列表默认为ArrayList。

public void toListTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    List<String> ll = list.stream().collect(Collectors.toList());
    System.out.println(ll);
}

// 打印结果:[123, 456, 789, 1101, 212121121, asdaa, 3e3e3e, 2321eew]
2.1.3 toSet

将流中的元素放置到一个无序集set中去。默认为HashSet。

public void toSetTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    Set<String> ll = list.stream().collect(Collectors.toSet());
    System.out.println(ll);
}

// 打印结果:[123, 456, 789, 1101, 212121121, asdaa, 3e3e3e, 2321eew]
2.1.4 joining

joining的目的是将流中的元素全部以字符序列的方式连接到一起,可以指定连接符,甚至是结果的前后缀。

public void joiningTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    // 无参方法
    String s = list.stream().collect(Collectors.joining());
    System.out.println(s);
    // 指定连接符
    String ss = list.stream().collect(Collectors.joining("-"));
    System.out.println(ss);
    // 指定连接符和前后缀
    String sss = list.stream().collect(Collectors.joining("-","S","E"));
    System.out.println(sss);
}

// 无参连接符:1234567891101212121121asdaa3e3e3e2321eew
// 指定连接符:123-456-789-1101-212121121-asdaa-3e3e3e-2321eew
// 指定连接符和前后缀:S123-456-789-1101-212121121-asdaa-3e3e3e-2321eewE
2.1.5 mapping

这个映射是首先对流中的每个元素进行映射,即类型转换,然后再将新元素以给定的Collector进行归纳。

public void mapingTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    List<Integer> ll = list.stream().limit(5).collect(Collectors.mapping(Integer::valueOf, Collectors.toList()));
    System.out.println(ll);
}

// limit(5)截取字符串列表前5个元素
// 打印结果:[123, 456, 789, 1101, 212121121]
2.1.6 collectingAndThen

该方法是在归纳动作结束之后,对归纳的结果进行再处理。

public void collectingAndThenTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    int ll = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),e -> e.size()));
    System.out.println(ll);
}

// 打印结果:8
2.1.7 counting

该方法用于计数。

public void countingTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    long ll = list.stream().collect(Collectors.counting());
    System.out.println(ll);
}

// 打印结果:8
2.1.8 minBy/maxBy

生成一个用于获取最小/最大值的Optional结果的Collector。

public void maxByAndMinByTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    // 获取最大值
    Optional<String> ll = list.stream().collect(Collectors.maxBy((a, b) -> a.length() - b.length()));
    System.out.println(ll);
    // 获取最小值
    Optional<String> lll = list.stream().collect(Collectors.minBy((a, b) -> a.length() - b.length()));
    System.out.println(lll);
}

// 获取最大值:Optional[212121121]
// 获取最小值:Optional[212121121]
2.1.9 summingInt/summingLong/summingDouble

生成一个用于求元素和的Collector,首先通过给定的mapper将元素转换类型,然后再求和。

参数的作用就是将元素转换为指定的类型,最后结果与转换后类型一致。

public void maxByAndMinByTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    // int类型
    int i = list.stream().limit(3).collect(Collectors.summingInt(Integer::valueOf));
    System.out.println(i);
    // long类型
    long l = list.stream().limit(3).collect(Collectors.summingLong(Long::valueOf));
    System.out.println(l);
    // double类型
    double d = list.stream().limit(3).collect(Collectors.summingDouble(Double::valueOf));
    System.out.println(d);
}

// int类型:1368
// long类型:1368
// double类型:1368.0
2.1.10 averagingInt/averagingLong/averagingDouble

生成一个用于求元素平均值的Collector,首选通过参数将元素转换为指定的类型。

参数的作用就是将元素转换为指定的类型,求平均值涉及到除法操作,结果一律为Double类型。

public void averagingTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    double i = list.stream().limit(3).collect(Collectors.averagingInt(Integer::valueOf));
    System.out.println(i);
    double l = list.stream().limit(3).collect(Collectors.averagingLong(Long::valueOf));
    System.out.println(l);
    double d = list.stream().limit(3).collect(Collectors.averagingDouble(Double::valueOf));
    System.out.println(d);
    // 涉及到处罚一律为 double类型
}

// 打印结果:456.0 456.0 456.0
2.1.11 reducing

reducing方法有三个重载方法,其实是和Stream里的三个reduce方法对应的,二者是可以替换使用的,作用完全一致,也是对流中的元素做统计归纳作用。

public void averagingTest() {
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    double i = list.stream().limit(3).collect(Collectors.averagingInt(Integer::valueOf));
    System.out.println(i);
    double l = list.stream().limit(3).collect(Collectors.averagingLong(Long::valueOf));
    System.out.println(l);
    double d = list.stream().limit(3).collect(Collectors.averagingDouble(Double::valueOf));
    System.out.println(d);
    // 涉及到处罚一律为 double类型
}

// 无初始值的情况:Optional[13]
// 有初始值的情况:9
// 有初始值:13
2.1.12 groupingBy

这个方法是用于生成一个拥有分组功能的Collector,它也有三个重载方法

groupingBy方法还有并发版的groupingByConcurrent,功能基本一致,只是返回的Collector是并行的。

public void groupingByTest(){
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    // 只需一个分组参数classifier,内部自动将结果保存到一个map中,每个map的键为?类型(即classifier的结果类型),值为一个list,这个list中保存在属于这个组的元素。
    Map<Integer,List<String>> s = list.stream().collect(Collectors.groupingBy(String::length));
    System.out.println(s);
    // 在上面方法的基础上增加了对流中元素的处理方式的Collector,比如上面的默认的处理方法就是Collectors.toList()
    Map<Integer,List<String>> ss = list.stream().collect(Collectors.groupingBy(String::length, Collectors.toList()));
    System.out.println(ss);
    // 在第二个方法的基础上再添加了结果Map的生成方法。
    Map<Integer,Set<String>> sss = list.stream().collect(Collectors.groupingBy(String::length,HashMap::new,Collectors.toSet()));
    System.out.println(sss);
}

// 执行结果s:{3=[123, 456, 789], 4=[1101], 5=[asdaa], 6=[3e3e3e], 7=[2321eew], 9=[212121121]}
// 执行结果ss:{3=[123, 456, 789], 4=[1101], 5=[asdaa], 6=[3e3e3e], 7=[2321eew], 9=[212121121]}
// 执行结果sss:{3=[123, 456, 789], 4=[1101], 5=[asdaa], 6=[3e3e3e], 7=[2321eew], 9=[212121121]}
2.1.13 partitioningBy

该方法将流中的元素按照给定的校验规则的结果分为两个部分,放到一个map中返回,map的键是Boolean类型,值为元素的列表List。

该方法有两个重载方法

public void partitioningByTest(){
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    // 只需一个校验参数predicate
    Map<Boolean,List<String>> map = list.stream().collect(Collectors.partitioningBy(e -> e.length()>5));
    System.out.println(map);
    // 在上面方法的基础上增加了对流中元素的处理方式的Collector,比如上面的默认的处理方法就是Collectors.toList()
    Map<Boolean,Set<String>> map2 = list.stream().collect(Collectors.partitioningBy(e -> e.length()>6,Collectors.toSet()));
    System.out.println(map2);
}

// 打印结果map:{false=[123, 456, 789, 1101, asdaa], true=[212121121, 3e3e3e, 2321eew]}
// 打印结果map2:{false=[123, 456, 1101, 789, 3e3e3e, asdaa], true=[212121121, 2321eew]}

2.1.14 toMap

toMap方法是根据给定的键生成器和值生成器生成的键和值保存到一个map中返回,键和值的生成都依赖于元素,可以指定出现重复键时的处理方案和保存结果的map。

第一种方式中,如果不添加limit限制,就会抛出异常。

还有并发的版本:toConcurrentMap,同样三种重载方法,与toMap基本一致,只是它最后使用的map是并发Map:ConcurrentHashMap。

public void toMapTest(){
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    // 指定键和值的生成方式keyMapper和valueMapper
    Map<String,String> map = list.stream().limit(3).collect(Collectors.toMap(e -> e.substring(0,1),e -> e));
    System.out.println(map);
    // 在上面方法的基础上增加了对键发生重复时处理方式的mergeFunction,比如上面的默认的处理方法就是抛出异常
    Map<String,String> map1 = list.stream().collect(Collectors.toMap(e -> e.substring(0,1),e->e,(a,b)-> b));
    System.out.println(map1);
    // 在第二个方法的基础上再添加了结果Map的生成方法。
    Map<String,String> map2 = list.stream().collect(Collectors.toMap(e -> e.substring(0,1),e->e,(a,b)-> b,HashMap::new));
    System.out.println(map2);
}

// 打印结果map:{1=123, 4=456, 7=789}
// 打印结果map1:{a=asdaa, 1=1101, 2=2321eew, 3=3e3e3e, 4=456, 7=789}
// 打印结果map2:{a=asdaa, 1=1101, 2=2321eew, 3=3e3e3e, 4=456, 7=789}

2.1.15 summarizingInt/summarizingLong/summarizingDouble

这三个方法适用于汇总的,返回值分别是IntSummaryStatistics,LongSummaryStatistics,DoubleSummaryStatistics。

在这些返回值中包含有流中元素的指定结果的数量、和、最大值、最小值、平均值。所有仅仅针对数值结果。

public void summarizingTest(){
    List<String> list = Arrays.asList("123","456","789","1101","212121121","asdaa","3e3e3e","2321eew");
    IntSummaryStatistics intSummary = list.stream().collect(Collectors.summarizingInt(String::length));
    System.out.println(intSummary);
    LongSummaryStatistics longSummary = list.stream().limit(4).collect(Collectors.summarizingLong(Long::valueOf));
    System.out.println(longSummary);
    DoubleSummaryStatistics doubleSummary = list.stream().limit(3).collect(Collectors.summarizingDouble(Double::valueOf));
    System.out.println(doubleSummary);
}

// 打印结果intSummary:IntSummaryStatistics{count=8, sum=40, min=3, average=5.000000, max=9}
// 打印结果longSummary:LongSummaryStatistics{count=4, sum=2469, min=123, average=617.250000, max=1101}
// 打印结果doubleSummary:DoubleSummaryStatistics{count=3, sum=1368.000000, min=123.000000, average=456.000000, max=789.000000}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AiLi0617

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值