Stream()------Java8-流简化集合操作


Java8中提供了Stream对集合操作作出了极大的简化,学习了Stream之后,我们以后不用使用for循环就能对集合作出很好的操作。

一、流的初始化与转换:

Java中的Stream的所有操作都是针对流的,所以,使用Stream必须要得到Stream对象:
1、初始化一个流:
Stream stream = Stream.of(“a”, “b”, “c”);
2、数组转换为一个流:
String [] strArray = new String[] {“a”, “b”, “c”};
stream = Stream.of(strArray);
或者
stream = Arrays.stream(strArray);
3、集合对象转换为一个流(Collections):
List list = Arrays.asList(strArray);
stream = list.stream();
4、集合对象转换为一个并行流(Collections):
List list = Arrays.asList(strArray);
stream = list.parallelstream();

二、Stream的特性

stream()优点:无存储。对大数据量的集合的循环处理,stream拥有极大的优势,完全可以用stream去代替for循环。

stream()介绍:是java对集合操作的优化,相较于迭代器,使用Stream的速度非常快,并且它支持并行方式处理集合中的数据,默认情况能充分利用cpu的资源。同时支持函数式编程,代码非常简洁。

1 Stream是一种用来计算数据的流,它本身并没有存储数据。你可以认为它是对数据源的一个映射或者视图。

2 Stream的工作流程是:获取数据源->进行一次或多次逻辑转换操作->进行归约操作形成新的流(最后可以将流转换成集合)

3 stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。
4 为函数式编程而生。对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。
5 惰式执行:stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
6 可消费性:stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。

中间操作惰性执行:一个流后面可以跟随0到多个中间操作,主要目的是打开流,并没有真正的去计算,而是做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历,并没有消耗资源。
还有多个中间操作的话,这里的时间复杂度并不是n个for循环,转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。可以这样简单的理解,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在Terminal操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。
流的末端操作只能有一次: 当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。之后如果想要操作就必须新打开流。

关于流被关闭不能再操作的异常:stream has already been operated upon or closed

意思是流已经被关闭了,这是因为当我们使用末端操作之后,流就被关闭了,无法再次被调用,如果我们想重复调用,只能重新打开一个新的流。

三、流的常见操作

package com.cainiao.Stream.流的基操;
import org.junit.Test;
import java.text.Collator;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test1 {
    // 公共方法 字符串转换为字符流
    public static Stream<Character> caseToCharacterStream(String s){
        List<Character> list = new ArrayList<>();
        for (char c : s.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }
    @Test
    public void filter(){
        List<String> list = Arrays.asList("abc","bce","刺客信条","张无忌","张无忌");
        //      1 filter 筛选符合条件的元素
        List<String> filter = list.stream().filter(s -> s.contains("a")).collect(Collectors.toList());
        System.out.println(filter); //[abc]
        System.out.println("................................................................");
        //      2 distinct 剔除重复元素(不适用对象元素,因为对象存储的是地址,不是固定数值)
        List<String> distinct = list.stream().distinct().collect(Collectors.toList());
        System.out.println(distinct); //[abc, bce, 刺客信条, 张无忌]
        System.out.println("................................................................");
        //      3 limit 获取流中前几个元素
        List<String> limit = list.stream().limit(2).collect(Collectors.toList());
        System.out.println(limit); //[abc, bce]
        System.out.println("................................................................");
        //      4 skip 获取流中除去前几个元素的其他所有元素(与limit相反)
        List<String> skip = list.stream().skip(2).collect(Collectors.toList());
        System.out.println(skip);//[刺客信条, 张无忌, 张无忌]
        System.out.println("................................................................");
        //      5 map 对流中所有元素做统一处理
        List<String> map = list.stream().map(s -> s + "yyds").collect(Collectors.toList());
        System.out.println(map); //[abcyyds, bceyyds, 刺客信条yyds, 张无忌yyds, 张无忌yyds]
        System.out.println("................................................................");
        //      6 flatmap的核心作用:把几个小的集合分别转换成流,再把各个流转换为一个流,流转集合,以此达到小集合合并到大集合的作用。
//      Stream<Character> characterStream = list.stream().flatMap(s -> caseToCharacterStream(s));
        Stream<Character> characterStream = list.stream().flatMap(Test1::caseToCharacterStream); //lamadar简化写法 返回字符流
        characterStream.forEach(System.out::println); //简写 characterStream.forEach(s -> System.out.println(s));
                   // 输出a
                         //b
                         //c
                         //b
                         //c
                         //e
                         //刺
                         //客
                         //信
                         //条
                         //张
                         //无
                         //忌
                         //张
                         //无
                         //忌
                   // 过程解析 :第(1)步 [a,b,c,y,y,d,s] [b,c,e,y,y,d,s] ... 第(2)步 【a,b,c,y,y,d,s,b,c,e,...,y,y,d,s】扁平化操作,把所有流合并为一个流再返回
        Stream<Stream<Character>> streamStream = list.stream().map(Test1::caseToCharacterStream);//返回流中流对象(相当于流的集合)
//        streamStream.forEach(System.out::println); 不能与下面的方法同时打开执行,因为此方法执行完会关闭流,然后下面那个遍历流中流的方法就会访问不到而报错
        /*java.util.stream.ReferencePipeline$Head@71c7db30
          java.util.stream.ReferencePipeline$Head@19bb089b
          java.util.stream.ReferencePipeline$Head@4563e9ab
          java.util.stream.ReferencePipeline$Head@11531931
          java.util.stream.ReferencePipeline$Head@5e025e70
        */
                // 过程解析:只有(1)步 [a,b,c,y,y,d,s] [b,c,e,y,y,d,s] ...就返回
        streamStream.forEach(s ->s.forEach(System.out::println)); //简写 streamStream.forEach(s ->s.forEach(c -> System.out.println(c)));
        // 输出a
        //b
        //c
        //b
        //c
        //e
        //刺
        //客
        //信
        //条
        //张
        //无
        //忌
        //张
        //无
        //忌
        System.out.println("................................................................");
        //      7 sorted 返回排序后的流
        List<String> sort = list.stream().sorted().collect(Collectors.toList());
        System.out.println(sort); //[abc, bce, 刺客信条, 张无忌, 张无忌]  不能排序汉语
              // 汉语排序
        List<String> sortChinese = list.stream().sorted(Collator.getInstance(Locale.CHINA)).collect(Collectors.toList());
        System.out.println(sortChinese); //[abc, bce, 刺客信条, 李光, 马超, 张无忌, 张无忌]
        // 汉语反序
        List<String> sortReverseChinese = list.stream().sorted(Collections.reverseOrder(Collator.getInstance(Locale.CHINA))).collect(Collectors.toList());
        System.out.println(sortChinese);
        System.out.println("................................................................");
        //      8 anyMatch 集合中是否有满足匹配条件的元素 boolean
        boolean= list.stream().anyMatch(s -> s.contains("刺"));
        System.out.println();//true
        System.out.println("................................................................");
        // 9 allMatch 集合中是否都满足匹配条件的元素 boolean
        boolean result = list.stream().allMatch(s -> s.length()>1);
        System.out.println(result);// true
        System.out.println("................................................................");
        // 9 noneMatch 集合中是否都不满足匹配条件的元素 boolean
        boolean none = list.stream().noneMatch(s -> s.length()>1);
        System.out.println(result);// true
        System.out.println("................................................................");
        // 10 findAny 返回集合中任意一个元素
        Optional<String> any = list.stream().findAny();
        System.out.println(any);//Optional[abc]
        if (any.isPresent()) System.out.println(any.get()); //判断是否有值,有值就返回取到的值,因为单行流方便的原因,会只取第一个。并行流会随机取
         // abc
        Optional<String> any2=list.parallelStream().findAny();
        System.out.println(any2);//Optional[刺客信条]
        System.out.println("................................................................");
        // 11 findFirst 返回集合中第一个元素
        Optional<String> first = list.stream().findFirst();
        first.ifPresent(System.out::println); // 简写 if(first.isPresent()) System.out.println(first.get());
        System.out.println("................................................................");
        // 12 foreach 对集合中元素进行遍历
        System.out.println("................................................................");
        // 13 collect 将流转换成其他像是 :list set map
        Set<String> toSet = list.stream().collect(Collectors.toSet()); //set  去重 无序
        System.out.println(toSet);//[abc, bce, 刺客信条, 张无忌]
        Map<String, String> toMap = list.stream().collect(Collectors.toMap(v -> v, v -> v, (oldvalue, newvalue) -> newvalue));//第一个是key ,第二个是value,第三个是遇到重复后的处理
        System.out.println(toMap);//{abc=abc, bce=bce, 刺客信条=刺客信条, 张无忌=张无忌}
        System.out.println("................................................................");
        // 14 reduce 将流中元素反复结合起来,得到一个值
                //方式一  acc是每一步结合的结果,item是初始值(未指定,默认为空)
        Optional<String> reduce1 = list.stream().reduce((acc, item) -> {
            return acc + item;
        });
        System.out.println(reduce1); // Optional[abcbce刺客信条张无忌张无忌]
        //方式二    acc是每一步结合的结果,item是初始值(未指定,默认为空)
        String reduce2 = list.stream().reduce("666",(acc, item) -> {
            return acc + item;
        });
        System.out.println(reduce2); // Optional[abcbce刺客信条张无忌张无忌]
        // 方式三
        // 15 获取集合中元素的数量
        long count = list.stream().count();
        System.out.println(count);//5
        // 16 获取最大值,最小值,平均值
        List<Integer> numList = Arrays.asList(1,2,5,10);
        //方法一:
        int max = numList.stream().mapToInt(x -> x).summaryStatistics().getMax();
        int min = numList.stream().mapToInt(x -> x).summaryStatistics().getMin();
        double average = numList.stream().mapToInt(x -> x).summaryStatistics().getAverage();
        long sum = numList.stream().mapToInt(x -> x).summaryStatistics().getSum();
        System.out.println("maxYear:"+max);
        System.out.println("minYear:"+min);
        System.out.println("average:"+average);
        System.out.println("sum:"+sum);
        //方法二:
        Integer maxNum = numList.stream().max(Integer::compareTo).get();
        Integer minNum = numList.stream().min(Integer::compareTo).get();
        System.out.println("maxNum:"+maxNum);
        System.out.println("minNum:"+minNum);


    }



}

四、流操作与传统循环操作的对比

以下内容引自《菜鸟教程》

import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Map;
 
public class Java8Tester {
   public static void main(String args[]){
      System.out.println("使用 Java 7: ");
        
      // 计算空字符串
      List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
      System.out.println("列表: " +strings);
      long count = getCountEmptyStringUsingJava7(strings);
        
      System.out.println("空字符数量为: " + count);
      count = getCountLength3UsingJava7(strings);
        
      System.out.println("字符串长度为 3 的数量为: " + count);
        
      // 删除空字符串
      List<String> filtered = deleteEmptyStringsUsingJava7(strings);
      System.out.println("筛选后的列表: " + filtered);
        
      // 删除空字符串,并使用逗号把它们合并起来
      String mergedString = getMergedStringUsingJava7(strings,", ");
      System.out.println("合并字符串: " + mergedString);
      List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        
      // 获取列表元素平方数
      List<Integer> squaresList = getSquares(numbers);
      System.out.println("平方数列表: " + squaresList);
      List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
        
      System.out.println("列表: " +integers);
      System.out.println("列表中最大的数 : " + getMax(integers));
      System.out.println("列表中最小的数 : " + getMin(integers));
      System.out.println("所有数之和 : " + getSum(integers));
      System.out.println("平均数 : " + getAverage(integers));
      System.out.println("随机数: ");
        
      // 输出10个随机数
      Random random = new Random();
        
      for(int i=0; i < 10; i++){
         System.out.println(random.nextInt());
      }
        
      System.out.println("使用 Java 8: ");
      System.out.println("列表: " +strings);
        
      count = strings.stream().filter(string->string.isEmpty()).count();
      System.out.println("空字符串数量为: " + count);
        
      count = strings.stream().filter(string -> string.length() == 3).count();
      System.out.println("字符串长度为 3 的数量为: " + count);
        
      filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
      System.out.println("筛选后的列表: " + filtered);
        
      mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
      System.out.println("合并字符串: " + mergedString);
        
      squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
      System.out.println("Squares List: " + squaresList);
      System.out.println("列表: " +integers);
        
      IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
        
      System.out.println("列表中最大的数 : " + stats.getMax());
      System.out.println("列表中最小的数 : " + stats.getMin());
      System.out.println("所有数之和 : " + stats.getSum());
      System.out.println("平均数 : " + stats.getAverage());
      System.out.println("随机数: ");
        
      random.ints().limit(10).sorted().forEach(System.out::println);
        
      // 并行处理
      count = strings.parallelStream().filter(string -> string.isEmpty()).count();
      System.out.println("空字符串的数量为: " + count);
   }
    
   private static int getCountEmptyStringUsingJava7(List<String> strings){
      int count = 0;
        
      for(String string: strings){
        
         if(string.isEmpty()){
            count++;
         }
      }
      return count;
   }
    
   private static int getCountLength3UsingJava7(List<String> strings){
      int count = 0;
        
      for(String string: strings){
        
         if(string.length() == 3){
            count++;
         }
      }
      return count;
   }
    
   private static List<String> deleteEmptyStringsUsingJava7(List<String> strings){
      List<String> filteredList = new ArrayList<String>();
        
      for(String string: strings){
        
         if(!string.isEmpty()){
             filteredList.add(string);
         }
      }
      return filteredList;
   }
    
   private static String getMergedStringUsingJava7(List<String> strings, String separator){
      StringBuilder stringBuilder = new StringBuilder();
        
      for(String string: strings){
        
         if(!string.isEmpty()){
            stringBuilder.append(string);
            stringBuilder.append(separator);
         }
      }
      String mergedString = stringBuilder.toString();
      return mergedString.substring(0, mergedString.length()-2);
   }
    
   private static List<Integer> getSquares(List<Integer> numbers){
      List<Integer> squaresList = new ArrayList<Integer>();
        
      for(Integer number: numbers){
         Integer square = new Integer(number.intValue() * number.intValue());
            
         if(!squaresList.contains(square)){
            squaresList.add(square);
         }
      }
      return squaresList;
   }
    
   private static int getMax(List<Integer> numbers){
      int max = numbers.get(0);
        
      for(int i=1;i < numbers.size();i++){
        
         Integer number = numbers.get(i);
            
         if(number.intValue() > max){
            max = number.intValue();
         }
      }
      return max;
   }
    
   private static int getMin(List<Integer> numbers){
      int min = numbers.get(0);
        
      for(int i=1;i < numbers.size();i++){
         Integer number = numbers.get(i);
        
         if(number.intValue() < min){
            min = number.intValue();
         }
      }
      return min;
   }
    
   private static int getSum(List numbers){
      int sum = (int)(numbers.get(0));
        
      for(int i=1;i < numbers.size();i++){
         sum += (int)numbers.get(i);
      }
      return sum;
   }
    
   private static int getAverage(List<Integer> numbers){
      return getSum(numbers) / numbers.size();
   }
}
执行以上脚本,输出结果为:

$ javac Java8Tester.java 
$ java Java8Tester
使用 Java 7: 
列表: [abc, , bc, efg, abcd, , jkl]
空字符数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
平方数列表: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9
随机数: 
-393170844
-963842252
447036679
-1043163142
-881079698
221586850
-1101570113
576190039
-1045184578
1647841045
使用 Java 8: 
列表: [abc, , bc, efg, abcd, , jkl]
空字符串数量为: 2
字符串长度为 3 的数量为: 3
筛选后的列表: [abc, bc, efg, abcd, jkl]
合并字符串: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
列表: [1, 2, 13, 4, 15, 6, 17, 8, 19]
列表中最大的数 : 19
列表中最小的数 : 1
所有数之和 : 85
平均数 : 9.444444444444445
随机数: 
-1743813696
-1301974944
-1299484995
-779981186
136544902
555792023
1243315896
1264920849
1472077135
1706423674
空字符串的数量为: 2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值