Java8-Stream流式计算

什么是Stream流式计算

大数据:存储 + 计算

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

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

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

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

串行处理操作:

  • Stream 在执行每一步中间操作时,并不会做实际的数据操作处理,而是将这些中间操作串联起来,生成一个数据处理链表,通过 Spliterator 迭代器进行数据处理。
  • 每执行一次迭代,就对所有的无状态的中间操作进行数据处理,而对有状态的中间操作,就需要迭代处理完所有的数据,再进行处理操作
  • 最后进行终结操作的数据处理。

并行处理操作(parallel()):

  • Stream 对中间操作基本跟串行处理方式是一样的
  • 终结操作中,Stream 将结合ForkJoin对集合进行切片处理,ForkJoin 框架将每个切片的处理结果 Join 合并起来

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

Stream流举例

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流常用方法

  • 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所指定的比较规则,比较出的最大值
Optional<T> max(Comparator<? super T> comparator);
  • 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,是泛型的表示方式,分别表示待比较的两个对象
1、o1大于o2,如果返回正整数,表示参数o1大于o2
2、o1等于o2,返回0/3、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>,从而能够达到我们的目的。

posted @ 2023-01-06 16:54  又一岁荣枯  阅读(253)  评论(0编辑  收藏  举报