Java8-Stream流式计算

什么是Stream流式计算

大数据:存储 + 计算

集合、MySQL 本质就是存储东西的;

计算都应该交给流来操作!

Stream是对集合功能的增强,它提供了各种非常便利、高效的聚合操作,可以大批量数据操作,同时再结合Lambda表达式,就可以极大的提高编程效率。

Stream的API提供了串行和并行两种模式进行操作数据。

Stream操作分为中间操作或者最终操作两种:

  • 中间操作,返回Stream本身,这样就可以将多个操作依次串起来例如,map、flatMap、filter、distinct、sorted、peek、limit、skip、parallel、sequential、unordered
  • 最终操作,返回一特定类型的计算结果例如,forEach、forEachOrdered、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst、findAny、iterator
public class User {
    private Integer id;
    private String name;
    private Integer age;
    // get、set
    // 有参、无参构造方法
    // tostring
}
package com.kuang.stream;
import java.util.Arrays; import java.util.List;
/** 
* 题目要求:一分钟内完成此题,只能用一行代码实现! * 现在有5个用户!筛选: 
* 1、ID 必须是偶数 
* 2、年龄必须大于23岁 
* 3、用户名转为大写字母 
* 4、用户名字母倒着排序
* 5、只输出一个用户!
*/
public class Test {   
    public static void main(String[] args) {   
        User u1 = new User(1,"a",21);        
        User u2 = new User(2,"b",22);    
        User u3 = new User(3,"c",23);       
        User u4 = new User(4,"d",24);      
        User u5 = new User(6,"e",25);      
        // 集合就是存储      
        List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
        // 计算交给Stream流      
        // lambda表达式、链式编程、函数式接口、Stream流式计算     
        list.stream()         
            .filter(u->{return u.getId()%2==0;})    
            .filter(u->{return u.getAge()>23;})        
            .map(u->{return u.getName().toUpperCase();})   
            // 这个只是字符串比较 如果是对象比较需要另一种方式
            .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})         
            .limit(1)
            .forEach(System.out::println); 
    } 
}

Stream的操作,看起来很像生产车间的流水线作业:

image-20200908193536299.png

常用方法:

  • iterator:返回迭代器对象

  • forEach:将调Stream中的每个元素,交给一个Consumer函数处理

    public class Test {
        public static void main(String[] args{
              Stream<String> stream = Stream.of("hello","world","briup");
              stream.forEach(System.out::println);    
        }
    }
    
  • count:统计流中的元素数,并返回结果

    public class Test {
        public static void main(String[] args{
      Stream<String> stream = Stream.of("hello","world","briup");
            System.out.println(stream.count());    
        }
    }
    
  • max:返回流中基于comparator所指定的比较规则,比较出的最大值

    image-20200908201255836.png

  • toArray:使用调用流中的元素,生成数组返回

  • filter:过滤

    public static void filter(){
        // 通过流将字符串转换成Stream格式的集合
        Stream<String> java = Stream.of("Java", "Python", "PHP");
        // 将包含字符串P的字符串筛选出来,并打印结果
        java.filter(str -> str.contains("P")).forEach(str -> System.out.println(str));
    }
    
  • distinct:去重

    System.out.println("所有user的年龄集合");
    List<Integer> userAgeList = list.stream().map(User::getAge).distinct().collect(Collectors.toList());
    System.out.println("userAgeList = " + userAgeList);
    
    所有user的年龄集合
    userAgeList = [``10``, ``12``, ``15``, ``25``, ``16``, ``14``, ``17``]
    
  • Collectors.toList():返回一个 Collector ,它将输入元素 List到一个新的 List

  • limit:limit返回包含前n个元素的流,当集合大小小于n时,则返回实际长度

    public static void filter(){
        // 通过流将字符串转换成Stream格式的集合
        Stream<String> java = Stream.of("Java", "Python", "PHP");
        // 将包含字符串P的字符串筛选出来,只输出一个
        java.filter(str -> str.contains("P")).limit(1).forEach(str -> System.out.println(str));
    }
    
  • sorted:sorted要求待比较的元素必须实现comparator接口

    • Comparator接口里面有一个compare方法,方法有两个参数T o1和T o2,是泛型的表示方式,分别表示待比较的两个对象

      • o1大于o2,如果返回正整数,表示参数o1大于o2
      • o1等于o2,返回0
      • o1小于o2,如果返回负整数,表示参数o1小于o2
      import java.util.Comparator;
      
      public class StudentComparator implements Comparator<StudentBean>{
      
      
          public int compare(StudentBean o1, StudentBean o2) {
      
              // 返回负数 说明比较器认为传进来得参数o1比o2小,所以o1在o2前面
              // 实际上从我们角度o1比o2大
              // 但是比较器只看返回得结果去判断o1是否大于o2从而进行升序降序
              if(o1.getScore() > o2.getScore()){
                  return -1;
              }else if(o1.getScore() < o2.getScore()){
                  return 1;
              }
              return 0;
          }
      }
      
  • map:映射

    假设我们希望筛选出所有专业为计算机科学的学生姓名,那么我们可以在filter筛选的基础之上,通过map将学生实体映射成为学生姓名字符串

    List<String> names = students.stream()
        .filter(student -> "计算机科学".equals(student.getMajor()))
        .map(Student::getName).collect(Collectors.toList());
    

    除了上面这类基础的map,java8还提供了mapToDouble(ToDoubleFunction mapper)mapToInt(ToIntFunction mapper)mapToLong(ToLongFunction mapper),这些映射分别返回对应类型的流,java8为这些流设定了一些特殊的操作,比如我们希望计算所有专业为计算机科学学生的年龄之和,那么我们可以实现如下:

    int totalAge = students.stream()
                        .filter(student -> "计算机科学".equals(student.getMajor()))
                        .mapToInt(Student::getAge).sum();
    
    
  • 调用串行Stream的parallel()方法,可以将其转换并行Stream

  • flatMap:flatMap与map的区别在于 flatMap是将一个流中的每个值都转成一个个流,然后再将这些流扁平化成为一个流

    举例说明,假设我们有一个字符串数组

    String[] strs = {"java8", "is", "easy", "to", "use"};

    我们希望输出构成这一数组的所有非重复字符,那么我们可能首先会想到如下实现:

    List<String[]> distinctStrs = Arrays.stream(strs)
                                  // 映射成为Stream<String[]>
                                    .map(str -> str.split(""))  
                                    .distinct()
                                    .collect(Collectors.toList());
    

    在执行map操作以后,我们得到是一个包含多个字符串(构成一个字符串的字符数组)的流,此时执行

    distinct操作是基于在这些字符串数组之间的对比,所以达不到我们希望的目的,此时的输出为:

    [j, a, v, a, 8]
    [i, s]
    [e, a, s, y]
    [t, o]
    [u, s, e]
    
  • 方法 说明
    filter 元素过滤,对Stream对象按照指定的Predicate进行过滤,返回的Strema对象中仅包含满足条件的元素
    map [mapToInt] [mapToLong] [mapToDouble] 元素一对一转换,使用传入的Function对象对Stream中所有元素进行映射处理,返回的Stream对象中的元素为原元素处理后的结果
    flatMap (flatMapToInt) (flatMapToLong) (flatMapToDouble) 元素一对多转换,对Stream对象中的所有元素进行操作,每个元素会有一个或多个结果,然后将所有的元素组合成一个统一的Stream并返回
    distinct 元素去重,返回去重后的Stream对象
    sorted [sorted(Comparator<? super T> comparator)] 元素排序,返回排序后的Stream对象
    limit 元素截取,返回有限个元素组成新的Stream对象
    skip 元素跳过,抛弃前指定个元素后,使用剩下的元素组成新的Stream对象返回
    peek 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数即引用的方法,当Stream每个元素被消费的时候都会先执行新Stream给定的方法

    distinct只有对于一个包含多个字符的流进行操作才能达到我们的目的,即对Stream<String>进行操作。

    此时flatMap就可以达到我们的目的:

    List<String> distinctStrs = Arrays.stream(strs)
          // 映射成为Stream<String[]>
          .map(str -> str.split(""))  
          // 扁平化为Stream<String>
          .flatMap(Arrays::stream)  
          .distinct()
          .collect(Collectors.toList());
    

    flatMap将由map映射得到的Stream<String[]>,转换成由各个字符串数组映射成的流Stream<String>,再将这些小的流扁平化成为一个由所有字符串构成的大流Steam<String>,从而能够达到我们的目的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342