java8之StreamAPI

Stream(流):

什么是stream(流):Stream是一个来自数据源的元素队列并支持聚合操作
    元素:是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算
    数据源:流的来源。可以是集合,数组,I/O channel, 产生器generator 等
    聚合操作:类似SQL语句一样的操作,如:filter, map, reduce, find, match, sorted等
​
Stream操作的两个基础特征:
    Pipelining: 中间操作都会返回流对象本身
        这样多个操作可以串联成一个管道,如同流式风格(fluent style)
        这样做可以对操作进行优化,比如延迟执行(laziness)和短路( short-circuiting)
    内部迭代: 
        以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代,这叫做外部迭代
        Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现
注意: 
    1. Stream自己不会存储元素
    2. Stream不会改变原对象,相反他们会返回一个持有结果的新Stream
    3. Stream操作是延迟执行,这意味着他们会等到需要结果的时候才执行

Stream操作步骤:

1.创建流(即初始化流)
2.中间操作:Intermediate
    一个流可以后面跟随零个或多个intermediate操作 
    做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用
    
    常见中间操作: 
        filter distinct sorted peek limit
        skip parallel sequential unordered
        map (mapToInt, flatMap 等)
3.终止操作:Terminal
    一个流只能有一个terminal操作,执行多个terminal操作会报错:stream has already been operated upon or closed
    Terminal 操作的执行,才会真正开始流的遍历并且会生成一个结果或者一个 side effect
    
    常见终止操作:
        forEach forEachOrdered toArray reduce collect
         min max count anyMatch allMatch noneMatch
         findFirst findAny iterator
    
    短路操作:Short-circuiting
        对于一个intermediate 操作:
            如果它接受的是一个无限大(infinite/unbounded)的Stream,但返回一个有限的新 Stream
        对于一个terminal 操作:
            如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果
        常见短路操作:
            anyMatch allMatch noneMatch findFirst findAny limit

流的创建:

方式一:Collection接口相关方法 将集合转换为流
    default Stream< E> stream();  //返回一个串行流 
    default Stream< E> parallelStream(); //返回一个并行流
    
    示例:
        List<String> list = Arrays.asList("a","ab","abc","abcd","dh","");
        Stream<String> listToStream = list.stream();//串行流
        Stream<String> parallelStream = list.parallelStream();//并行流
        
    并行流通过默认的ForkJoinPool,可能提高你的多线程任务的速度。并行流在遍历时可能是无序的
    
方式二: Arrays类的静态方法 stream() 将数组转换为流
    public static <T> Stream<T> stream(T[] array)
    
    示例:
        String [] strArray = new String[] {"a", "b", "c","d"};
        Stream<String> arrayToStream = Arrays.stream(strArray);
        
方式三:Stream接口静态方法    of() 初始化流
    public static<T> Stream<T> of(T... values)
    
    示例:
        Stream<String> stream = Stream.of("a","b","c","d");
​
方式四:Stream接口静态方法    iterate()、generat()创建无限流    
    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
    public static<T> Stream<T> generate(Supplier<T> s)
    
    示例:
        //0 2
        Stream<Integer> iterateStream = Stream.iterate(0, (x) -> x+2).limit(2); 
        //0.7959655194696649 0.04986900509440961 0.4258300512930294 0.6815133817071739
        Stream<Double> generateStrem = Stream.generate(Math::random).limit(4);

流的常用操作:

  • 1.筛选/过滤:filter/distinct/limit/skip
方法描述
filter(Predicate p)接收 Lambda , 从流中排除某些元素
distinct()筛选,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素
limit(long maxSize)截断流,使其元素不超过给定数量
skip(long n)跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素 不足 n 个,则返回一个空流。与 limit(n) 互补
    示例:
        Stream<String> strStream = Stream.of("pugb","king","lol","ow","solo","ow","");
        
        strStream
            .filter(s -> s.length()>0)//过滤字符串长度小于0的元素
            .distinct() //元素去重 (需要重写 hashcode和 equals方法)
            .skip(2)    //跳过流的前两个元素
            .limit(2)   //从第三个元素起取2个元素
            .forEach(System.out::println);//内部迭代流中的元素
            
    执行结果:lol ow
  • 2.映射:map/flatMap/...
map(Function f)接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素
mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream
mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream
mapToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream
flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
    示例:
        List<String> list = Arrays.asList("a","ab","abc","abcd","dh");
        list.stream()
            .map(String::toUpperCase)//将元素转为大写
            .forEach(System.out::println);//内部迭代流中的元素
       System.out.println("---------------------------------------")
       
       String[] arrayOfWords = {"Hello", "World"};
       List<String> words = Arrays.asList(arrayOfWords);
       words.stream()
            .map(w -> split(""))
            .flatMap(Arrays::stream)
            .distinct()
            .forEach(System.out::println);
     执行结果:
         A AB ABC ABCD DH
         --------------------------------------------------
         H
         l
         o
         W
         r
         d
  • 3.排序:sorted 
方法描述
sorted()产生一个新流,其中按自然顺序排序
sorted(Comparator comp)产生一个新流,其中按比较器顺序排序
    示例:
        List<Integer> sortList = Arrays.asList(1,2,13,4,15,6,17,8,19);
        sortList.stream()
            .sorted()//排序
            .forEach(System.out::println);//内部迭代流中的元素
            
        sortList.stream()
            .sorted(Integer::compare)//排序
            .forEach(System.out::println);//内部迭代流中的元素
            
    执行结果:1 2 4 6 8 13 15 17 19
  • 4.查找与匹配: 
方法描述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素总数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c)内部迭代(使用 Collection 接口需要用户去做迭 代,称为外部迭代。相反,Stream API 使用内部 迭代——它帮你把迭代做了)
    示例:
        List<String> matchList = Arrays.asList("pugb","king","lol","ow","solo","ow","");
        boolean anyMatch = matchList.stream().anyMatch(str -> str.equals("king"));
        boolean noneMatch = matchList.stream().noneMatch(String::isEmpty);
        boolean allMatch = matchList.stream().allMatch(String::isEmpty);
        System.out.println(anyMatch);   //true
        System.out.println(noneMatch);  //false
        System.out.println(allMatch);   //false
​
        Optional<String> findFirst = matchList.stream().findFirst();
        System.out.println(findFirst.get());    //pugb
        
        Optional<String> findAny = matchList.stream().filter(s -> s.equals("king")).findAny();
        System.out.println(findAny.get());  //king
  •  5.统计:max/min/avg/sum

    示例:
        List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
        IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
        System.out.println("列表中最大的数 : " + stats.getMax());      //19                   
        System.out.println("列表中最小的数 : " + stats.getMin());      //1                    
        System.out.println("所有数之和 : " + stats.getSum());        //85                   
        System.out.println("平均数 : " + stats.getAverage());      // 9.444444444444445   
        System.out.println("=========================================================");
        
        OptionalInt max = integers.stream().mapToInt((x) ->x).max();
        OptionalInt min = integers.stream().mapToInt((x) ->x).min();
        int sum = integers.stream().mapToInt((x) ->x).sum();
        OptionalDouble avg = integers.stream().mapToInt((x) ->x).average();
        System.out.println("最大值: " +max.getAsInt());        //19
        System.out.println("最小值: " +min.getAsInt());        //1
        System.out.println(" 和:"  +sum);                        //85
        System.out.println("平均值: "  +avg.getAsDouble());    // 9.444444444444445
        System.out.println("=========================================================");
        
        //Stream中只有max和min两个方法 sum/avg需转换为对应的包装类Stream计算
        Optional<Integer> maxInteger = integers.stream().max(Integer::compare);
        Optional<Integer> minInteger = integers.stream().min(Integer::compare);
        System.out.println(maxInteger.get());       //19
        System.out.println(minInteger.get());       //1
  •  6.归约:reduce
方法描述
reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来,得到一个值。 返回 T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。 返回 Optional< T>
    备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它 来进行网络搜索而出名
    
    示例:
        //求和
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println(sum);        //55 
  • 7.收集:collect 
    准备Employee类:重写hashCode和equals方法
        public class Employee {
            private Integer id;
            private String name;
            private Integer age;
            private Double salary;
            private Integer status;
            
            //省略getter/setter/toString/hashCode/equals方法
        }
    定义集合:
        List<Employee> emps = Arrays.asList(
                  new Employee(101, "林青霞", 28, 9889.99),
                  new Employee(102, "东方不败", 29, 4329.85),
                  new Employee(103, "周星驰", 40, 1233.88),
                  new Employee(104, "大圣", 500, 5000.44),
                  new Employee(105, "张无忌", 15, 3000.09),
                  new Employee(102, "东方不败", 29, 4329.85)
          );
    收集示例:
        emps.stream()
            .map(Employee::getName)//将员工姓名转为stream
            .collect(Collectors.toList())//将员工姓名stream转为List集合
            .forEach(System.out::println);
        emps.stream()
            .map(Employee::getName)//将员工姓名转为stream
            .collect(Collectors.toSet())//将员工姓名stream转为Set集合
            .forEach(System.out::println);
        emps.stream()
        .map(Employee::getName)//将员工姓名转为stream
        .collect(Collectors.toCollection(HashSet::new))//将员工姓名stream转为HashSet集合
        .forEach(System.out::println);

        执行结果:
            林青霞 东方不败 周星驰 大圣 张无忌 东方不败
            ------------------- 
            周星驰 林青霞 大圣 东方不败 张无忌 
            ------------------- 
            周星驰 林青霞 大圣 东方不败 张无忌
    统计示例:
        Long count = emps.stream().collect(Collectors.counting());
        System.out.println("员工个数:" + count);
        Double avgSalary = emps.stream().
                collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println("平均工资:" + avgSalary);
        Double sumSalary= emps.stream().
                collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println("总工资:" + sumSalary);
        Optional<Employee> maxSalary = emps.stream()
                .collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
        System.out.println("最高工资员工:" + maxSalary.get());
        Optional<Double> minSalary = emps.stream()
                 .map(Employee::getSalary)
                 .collect(Collectors.minBy(Double::compare));
        System.out.println("最低工资:" + minSalary.get());
        //统计分析
        DoubleSummaryStatistics doubleSummaryStatistics = emps.stream()
                 .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println("平均工资:" + doubleSummaryStatistics.getAverage());
        System.out.println("最高工资:" + doubleSummaryStatistics.getMax());
        System.out.println("最低工资:" + doubleSummaryStatistics.getMin());
        System.out.println("总工资:" + doubleSummaryStatistics.getSum());
        //拼接
        String join = emps.stream()
                 .map(Employee::getName)//将员工姓名转为stream
                 .collect(Collectors.joining(",", "--", "--"));//拼接符"," 前缀"--" 后缀"--"
        System.out.println(join);
        
        
        执行结果:
            员工个数:6
            平均工资:4630.683333333333
            总工资:27784.1
            最高工资员工:Employee [id=101, name=林青霞, age=28, salary=9889.99, status=null]
            最低工资:1233.88
            平均工资:4630.683333333333
            最高工资:9889.99
            最低工资:1233.88
            总工资:27784.1
            --林青霞,东方不败,周星驰,大圣,张无忌,东方不败--
             
    收集分组:
        Map<String, List<Employee>> group = emps.stream()
                .collect(Collectors.groupingBy(Employee::getName));
        System.out.println(group);
        
        执行结果:
            {
             周星驰=[Employee [id=103, name=周星驰, age=40, salary=1233.88, status=null]],
             林青霞=[Employee [id=101, name=林青霞, age=28, salary=9889.99, status=null]], 
             大圣=[Employee [id=104, name=大圣, age=500, salary=5000.44, status=null]],
             东方不败=[Employee [id=102, name=东方不败, age=29, salary=4329.85, status=null],                          
                      Employee [id=102, name=东方不败, age=29, salary=4329.85, status=null]
             ],
             张无忌=[Employee [id=105, name=张无忌, age=15, salary=3000.09, status=null]]}
    多级分组:
        Map<String, Map<String, List<Employee>>> moreGroup = emps.stream()
                .collect(Collectors.groupingBy(Employee::getName, Collectors.groupingBy((e) -> {
                    if (e.getAge() < 30) return "青年";
                    else if (e.getAge() < 50) return "中年";
                    else return "老年";
                })));
        System.out.println(moreGroup);
        
        执行结果:
            {
            周星驰={中年=[Employee [id=103, name=周星驰, age=40, salary=1233.88, status=null]]},             
            林青霞={青年=[Employee [id=101, name=林青霞, age=28, salary=9889.99, status=null]]},             
            大圣={老年=[Employee [id=104, name=大圣, age=500, salary=5000.44, status=null]]}, 
            东方不败={青年=[Employee [id=102, name=东方不败, age=29, salary=4329.85, status=null],                           
                          Employee [id=102, name=东方不败, age=29, salary=4329.85, status=null]]
            }, 
            张无忌={青年=[Employee [id=105, name=张无忌, age=15, salary=3000.09, status=null]]}}

 Collector 接口中方法的实现决定了如何对流执行收集操作(如收 集到 List、Set、Map)。但是 Collectors 实用类 供了很多静态 方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

方法返回类型作用
toListList<T>把流中元素收集到List
List<Employee> emps= list.stream().collect(Collectors.toList());
toSetSet<T>把流中元素收集到Set
Set<Employee> emps= list.stream().collect(Collectors.toSet());
toCollectionCollection<T>把流中元素收集到创建的集合
Collection<Employee>emps=list.stream().collect(Collectors.toCollection(ArrayList::new));
countingLong计算流中元素的个数
long count = list.stream().collect(Collectors.counting());
summingIntInteger对流中元素的整数属性求和
inttotal=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingIntDouble计算流中元素Integer属性的平均 值
doubleavg= list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingIntIntSummaryStatistics收集流中Integer属性的统计值。 如:平均值
IntSummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joiningString连接流中每个字符串
String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxByOptional<T>根据比较器选择最大值
Optional<Emp>max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minByOptional<T>根据比较器选择最小值
Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing归约产生的类型从一个作为累加器的初始值 开始,利用BinaryOperator与 流中元素逐个结合,从而归 约成单个值
inttotal=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
collectingAndThen转换函数返回的类型包裹另一个收集器,对其结 果转换函数
inthow= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingByMap<K, List<T>>根据某属性值对流分组,属 性为K,结果为V
Map<Emp.Status, List<Emp>> map= list.stream() .collect(Collectors.groupingBy(Employee::getStatus));
partitioningByMap<Boolean,List<T>>根据true或false进行分区
Map<Boolean,List<Emp>>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage));

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值