前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDK8系列之Stream API入门教程和示例

JDK8系列之Stream API入门教程和示例

作者头像
SmileNicky
发布2021-07-21 14:43:09
6490
发布2021-07-21 14:43:09
举报
文章被收录于专栏:Nicky's blogNicky's blog

JDK8系列之Stream API入门教程和示例

前面的章节的学习中,我们学习了jdk8的新特性,lambada表达式、方法引用、函数式接口等等,接着本博客继续JDK8的一个比较重要的特性,JDK8 Stream API

1、什么是Jdk8 Stream?

Stream api是jdk8的新特性,使用jdk中java.util.stream里库,这种风格将元素集合看作一种stream,stream在管道中传输,在管道节点经过筛选、排序、聚合等操作,然后由terminal操作得到结果

在这里插入图片描述
在这里插入图片描述

2、Jdk8 Stream优点是什么?

  • Java 8 中的 Stream 是对集合(Collection)对象功能的增强,Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码
  • 同时Jdk8 Stream api提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势

  • Stream stream() : 返回一个顺序流
  • Stream parallelStream() : 返回一个并行流

3、Jdk8 Stream的特征

  • 不存储数据:Stream数据来源于数据源,但是本身是不存储数据元素的,而是将管道的数据元素传递给操作
  • 函数式编程:流的操作不会修改数据
  • 延迟操作:流的操作,如Filter,map等中间操作是可以延迟的,只有到terminal操作才会将操作顺序执行
  • 可以解绑:stream api有些操作是要求在有限的时间完成的,比如limit(n) 或 findFirst(),这些操作访问到有限的元素后就可以返回
  • 一次性消费:流的元素只能访问一次,如果你想重新访问流的元素,你得重新生成一个新的流。

4、Stream流的所有操作函数

  • 中间操作(intermediate operation)
    • 无状态(Stateless)
      • unordered()
      • filter()
      • map()
      • mapToInt()
      • mapToLong()
      • mapToDouble
      • flatMap()
      • flatMapToInt()
      • flatMapToLong()
      • flatMapToDouble()
      • peek()
    • 有状态(Stateful)
      • distinct()
      • sorted()
      • limit()
      • skip()
  • terminal 操作(terminal operation)
    • 非短路操作
      • forEach()
      • forEachOrdered()
      • toArray()
      • reduce()
      • collect()
      • max()
      • min()
      • count()
    • 短路操作(short-circuiting)
      • anyMatch()
      • allMatch()
      • noneMatch()
      • findFirst()
      • findAny()

5、Stream流的创建方式

  • 由集合创建Stream
代码语言:javascript
复制
new ArrayList<>().stream();
  • 由数组创建Stream
代码语言:javascript
复制
Arrays.stream(new int[]{1,2,3})
  • 由值创建Stream
代码语言:javascript
复制
Stream<Integer> integerStream = Stream.of(1);
  • 由文件创建Stream
代码语言:javascript
复制
// example : 从文件读取数据
BufferedReader bufferedReader = null;
try {
    bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("D://javap.txt")));
} catch (FileNotFoundException e) {
    // ignore exception
    log.error("FileNotFoundException :{}",e);
}
Stream<String> lines = bufferedReader.lines();
lines.forEach(s -> {System.out.println(s);});

读取jar文件

代码语言:javascript
复制
 Stream<JarEntry> stream = new JarFile("").stream();

6、 Stream有限流和无限流

代码语言:javascript
复制
// example:创建有限流
IntStream.of(new int[]{1,2,3});
IntStream.range(1,10);
IntStream.rangeClosed(1,10);
//使用Pattern 将字符串分隔成流
Pattern pattern = compile(",");
Stream<String> streams = pattern.splitAsStream("a , b , c , d , e");
streams.forEach( System.out::print);
代码语言:javascript
复制
 // example :创建无限流
// 无限等比数列
 Stream<Integer> columns = Stream.iterate(1 , n -> n*2);
 // 生成无限随机数流
 Stream<Double> nums = Stream.generate(Math::random);
 // 无限数值流
 IntStream ints = new Random().ints();

7、intermediate operations

intermediate operations,又被称之为中间操作,中间操作会返回一个新的流,并且操作是延迟执行的,它不会修改原始的数据源,而且是由在终点操作开始的时候才真正开始执行

  • distinct 唯一
代码语言:javascript
复制
 // example :distinct 唯一
 List<String> distinctStrs = Stream.of("a", "b" , "c" , "d" , "e", "b")
         .distinct()
         .collect(Collectors.toList());
 System.out.println(String.format("distinct列表数据:%s" , distinctStrs));
  • filter 过滤
代码语言:javascript
复制
 // example : filter 过滤
 List<Integer> columns = Stream.of(1 ,2 ,-1,3,4,5,6,7,8,9)
         .filter(n -> n > 0)
         .collect(Collectors.toList());
 System.out.println(String.format("filter列表数据:%s" , columns));
  • map 映射
代码语言:javascript
复制
// example : map 映射
List<String[]> mapArras = Stream.of("hello","hi")
         .map(e -> e.split("") )
         .distinct()
         .collect(Collectors.toList());
 // List<String[]>类型的,不能直接打印
 mapArras.forEach(System.out::println);
  • filterMap 映射汇总
代码语言:javascript
复制
// example : flatMap 映射汇总
List<String> mapStrs = Stream.of("hello","hi")
         .map(e -> e.split(""))
         .flatMap(Arrays::stream)
         .distinct()
         .collect(Collectors.toList());
 // 通过.flatMap(Arrays::stream)转成string数据
 mapStrs.forEach(s->System.out.println(s));
  • limit 限制
代码语言:javascript
复制
// example :limit限制
List<Integer> ints = IntStream.range(1,1000).limit(10)
         .boxed()
         .collect(Collectors.toList());
 // 打印[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 System.out.println(ints);
  • peek 观察者 peek会提供一个消费函数,每个元素被消费时都会执行这个钩子函数
代码语言:javascript
复制
// example :peek  观察者
Arrays.stream(new String[]{"a","b","c","d","e"})
      // 每个元素被消费时都会执行这个钩子
      .peek(System.out::println)
      .count();
  • sorted 排序
代码语言:javascript
复制
//example :sorted 排序
List<Integer> sortedInts = Stream.of(1 ,9, 3, 2, 10,5,8)
    .sorted(
            (a , b) -> {
                return a >b ? 1 :-1;
            }
    )
    //.sorted(Comparator.comparingInt(a -> a))
    .collect(Collectors.toList());
System.out.println(sortedInts);
  • skip 跳过 skip 跳过丢弃了前n个元素的流,如果流中的元素小于或者等于n,则返回空的流
代码语言:javascript
复制
// example : skip 跳过
List<String> skipStrs = Stream.of("a", "b", "c", "d", "e","f","g","h","i")
         //丢弃了前n个元素的流,如果流中的元素小于或者等于n,则返回空的流
         .skip(2)
         .collect(Collectors.toList());
 System.out.println(skipStrs);

8、terminal operations

  • match 断言
代码语言:javascript
复制
public boolean 	allMatch(Predicate<? super T> predicate)
public boolean 	anyMatch(Predicate<? super T> predicate)
public boolean 	noneMatch(Predicate<? super T> predicate)

  • allMatch只有在所有的元素都满足断言时才返回true,否则flase,流为空时总是返回true
  • anyMatch只有在任意一个元素满足断言时就返回true,否则flase,
  • noneMatch只有在所有的元素都不满足断言时才返回true,否则flase
  • count 计数
代码语言:javascript
复制
 // example :count 计数
 String[] arr = new String[]{"a","b","c","d" , "e"};
 long count = Arrays.stream(arr).count();
 System.out.println(count);
  • collect 收集
代码语言:javascript
复制
// example : collect 收集
List<String> strs = Stream.of("a", "b" , "c" , "d" , "e", "b")
        .collect(Collectors.toList());
System.out.println(strs);

方法

返回类型

作用

toList()

List<T>

把流中元素收集到List,List<T> result = list.stream().collect(Collectors.toList());

toSet()

Set<T>

把流中元素收集到Set,Set<T> result = list.stream().collect(Collectors.toSet());

toCollection()

Collection<T>

把流中元素收集到集合,Collection<T> result = lsit.stream().collect(Collectors.toCollection(ArrayListL::new));

counting()

Long

计算流中元素的个数,long count = lsit.stream().collect(Collectors.counting());

summingInt()

Integer

对流中元素的整数属性求和,int total = lsit.stream().collect(Collectors.counting());

averagingInt

Double

计算元素Integer属性的均值,double avg = lsit.stream().collect(Collectors.averagingInt(Student::getAge));

summarizingInt

IntSummary

Statistics收集元素Integer属性的统计值,IntSummaryStatistics result = list.stream().collect(Collectors.summarizingInt(Student::getAge));

joining

Stream

连接流中的每个字符串,String str = list.stream().map(Student::getName).collect(Collectors.joining());

maxBy

Optional<T>

根据比较器选择最大值,Opetional<Student> max = list.stream().collect(Collectors.maxBy(comparingInt(Student::getAge)))

minBy

Optional<T>

根据比较器选择最小值,Optional<Student> min= list.stream().collect(Collectors.minBy(comparingInt(Student::getAge)));

reducing

规约产生的类型

从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值,int total = list.stream().collect(Collectors.reducing(0, Student::getAge, Integer::sum));

collectingAndThen

转换函数返回的类型

包裹另一个收集器,对其结果转换,int how = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));

groupingBy

Map<K, List<T>>

根据某属性值对流分组,属性为K,结果为,Map<Integer, List<Student>> map = list.stream().collect(Collectors.groupingBy(Student::getStatus));

partitioningBy

Map<Boolean, List<T>>

根据true或false进行分区,Map<Boolean, List<Student>> map = list.stream().collect(Collectors.partitioningBy(Student::getPass));

  • find 返回

  • findAny()返回任意一个元素,如果流为空,返回空的Optional,对于并行流来说,它只需要返回任意一个元素即可
  • findFirst()返回第一个元素,如果流为空,返回空的Optional。
  • forEach、forEachOrdered 遍历 forEach遍历流的每一个元素,对于有序流按照它的encounter order顺序执行,你可以使用forEachOrdered方法
代码语言:javascript
复制
Stream.of(1,2,3,4,5).forEach(System.out::println);
  • min、max

  • max返回流中的最大值,
  • min返回流中的最小值。
代码语言:javascript
复制
 // example :max、min
long minV = Stream.of(1,2,3,4,5).max(
        new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        }
).get();
long maxV = Stream.of(1,2,3,4,5).max(
    new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 - o2;
        }
    }
).get();
System.out.println(String.format("min value :%s , max value :%s", minV ,maxV));
  • reduce 归约 reduce是一个变成操作,依照某种运算规则依次执行,所以reduce可以用于做sum,min,max,average等等操作

方法

描述

reduce(BinaryOperator b)

可以将流中元素反复结合起来,得到一个值,返回 Optional

reduce(T iden, BinaryOperator b)

可以将流中元素反复结合起来,得到一个值,返回 T

reduce(U identity, BiFunction a, BinaryOperator combiner)

可以将流中元素反复结合起来,得到一个值,返回 Optional

代码语言:javascript
复制
 // example : reduce
 // reduce用于求和
 List<Integer> sumInts = Stream.of(1 ,2,3,4,5,6,7,8,9).collect(Collectors.toList());
 Optional<Integer> sum = sumInts.stream().reduce(Integer::sum);
 System.out.println(String.format("reduce计算的总值:%s" , sum));
  • toArray
代码语言:javascript
复制
// example : toArray
Integer[] integers = Stream.of(1 ,2,3,4,5,6,7,8,9).toArray(Integer[]::new);
System.out.println(integers);
  • concat 组合
代码语言:javascript
复制
 // example : concat 组合
 List<String> list1 = Stream.of("a","b","c").collect(Collectors.toList());;
 List<String> list2 = Stream.of("d","e","f").collect(Collectors.toList());;
 Stream.concat(list1.stream() , list2.stream()).forEach(System.out::println);

9、Stream灵活应用例子

  • 数据去重 数据去重,除了前面的distinct,也可以用TreeSet来做去重,总之,stream非常灵活,开发者可以根据自己理解,进行编程
代码语言:javascript
复制
handleModels.stream().collect(
Collectors.collectingAndThen(
        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(HandleModel::getUserCode))), ArrayList::new)
);
  • 数据筛选
代码语言:javascript
复制
 List<ControlVo> timeoutControlList = list.stream().filter(e-> e.getDays()!=null && e.getDays() < 0 ).sorted(Comparator.comparing(ControlVo::getDays)).collect(Collectors.toList());
  • PO、VO、DTO的转换
代码语言:javascript
复制
// PO转DTO
dtoList = handleModels.stream().map(e -> {
     HandleDto dto = new HandleDto ();
     BeanUtil.copyProperties(e, dto);
     return dto;
 }).collect(Collectors.toList());
  • 和Optional一起使用 list有数据时候,才进行遍历
代码语言:javascript
复制
Optional.ofNullable(list).ifPresent(
    hlist -> {
        hlist.stream().forEach((e) -> {
          
        });
});
  • 分挑存储 什么是分挑存储?就是根据集合实体类的一个字段,进行分组然后重新组合成新的集合

ps:按照StuffId进行分组

代码语言:javascript
复制
 Map<String, List<AttachmentDto>> attachmentGroup = 
attachmentDtos.stream()
.filter(item -> StringUtils.isNotBlank(item.getStuffId()))
.collect(Collectors.groupingBy(AttachmentDto::getStuffId));

10、附录参考资料

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-07-19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JDK8系列之Stream API入门教程和示例
    • 1、什么是Jdk8 Stream?
      • 2、Jdk8 Stream优点是什么?
        • 3、Jdk8 Stream的特征
          • 4、Stream流的所有操作函数
            • 5、Stream流的创建方式
              • 6、 Stream有限流和无限流
                • 7、intermediate operations
                  • 8、terminal operations
                    • 9、Stream灵活应用例子
                      • 10、附录参考资料
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档