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

Posted smileNicky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK8系列之Stream API入门教程和示例相关的知识,希望对你有一定的参考价值。

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
new ArrayList<>().stream();
  • 由数组创建Stream
Arrays.stream(new int[]{1,2,3})
  • 由值创建Stream
Stream<Integer> integerStream = Stream.of(1);
  • 由文件创建Stream
// 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文件

 Stream<JarEntry> stream = new JarFile("").stream();
  • 其它方法创建
    当然还有其它api也提供stream的创建,比如

    • BitSet数值流
    IntStream stream = new BitSet().stream();
    
    • Pattern 将字符串分隔成流
     //使用Pattern 将字符串分隔成流
     Pattern pattern = compile(",");
     Stream<String> streams = pattern.splitAsStream("a , b , c , d , e");
     streams.forEach( System.out::print);
    
    • …,等等

6、 Stream有限流和无限流

// 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);
 // 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 唯一
 // 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 过滤
 // 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 映射
// 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 映射汇总
// 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 限制
// 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会提供一个消费函数,每个元素被消费时都会执行这个钩子函数
// example :peek  观察者
Arrays.stream(new String[]{"a","b","c","d","e"})
      // 每个元素被消费时都会执行这个钩子
      .peek(System.out::println)
      .count();
  • sorted 排序
//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,则返回空的流
// 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 断言
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 计数
 // example :count 计数
 String[] arr = new String[]{"a","b","c","d" , "e"};
 long count = Arrays.stream(arr).count();
 System.out.println(count);
  • collect 收集
// 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());
averagingIntDouble计算元素Integer属性的均值,double avg = lsit.stream().collect(Collectors.averagingInt(Student::getAge));
summarizingIntIntSummaryStatistics收集元素Integer属性的统计值,IntSummaryStatistics result = list.stream().collect(Collectors.summarizingInt(Student::getAge));
joiningStream连接流中的每个字符串,String str = list.stream().map(Student::getName).collect(Collectors.joining());
maxByOptional<T>根据比较器选择最大值,Opetional<Student> max = list.stream().collect(Collectors.maxBy(comparingInt(Student::getAge)))
minByOptional<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));
groupingByMap<K, List<T>>根据某属性值对流分组,属性为K,结果为,Map<Integer, List<Student>> map = list.stream().collect(Collectors.groupingBy(Student::getStatus));
partitioningByMap<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方法
Stream.of(1,2,3,4,5).forEach(System.out::println);
  • min、max
  • max返回流中的最大值,
  • min返回流中的最小值。
 // 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
 // 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
// example : toArray
Integer[] integers = Stream.of(1 ,2,3,4,5,6,7,8,9).toArray(Integer[]::new);
System.out.println(integers);
  • concat 组合
 // 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非常灵活,开发者可以根据自己理解,进行编程
handleModels.stream().collect(
Collectors.collectingAndThen(
        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(HandleModel::getUserCode))), ArrayList::new)
);
  • 数据筛选
 List<ControlVo> timeoutControlList = list.stream().filter(e-> e.getDays()!=null && e.getDays() < 0 ).sorted(Comparator.comparing(ControlVo::getDays)).collect(Collectors.toList());

  • PO、VO、DTO的转换
// PO转DTO
dtoList = handleModels.stream().map(e -> {
     HandleDto dto = new HandleDto ();
     BeanUtil.copyProperties(e, dto);
     return dto;
 }).collect(Collectors以上是关于JDK8系列之Stream API入门教程和示例的主要内容,如果未能解决你的问题,请参考以下文章

JDK8系列之Method References教程和示例

JDK8系列之Lambda表达式教程和示例

JDK8版本之日期和时间API详解

stream操作常用API 示例详解

jdk8系列stream

JDK8系列之Optional API应该怎样用?