@Java知识点--Stream

别说谁变了你拦得住时间么 提交于 2020-07-28 07:04:12

概览

java8中有两个非常有名的改进,一个是Lambda表达式,一个是Stream。

Stream就是一个流,他的主要作用就是对集合数据进行查找过滤等操作。有点类似于SQL的数据库操作。Stream和Collection的区别就是:Collection只是负责存储数据,不对数据做其他处理,主要是和内存打交道。但是Stream主要是负责计算数据的,主要是和CPU打交道。

Stream语法讲解

Stream执行流程很简单,主要有三个,首先创建一个Stream,然后使用Stream操作数据,最后终止Stream。有点类似于Stream的生命周期。

@Data
public class Student {

    private Integer id;
    private String name;
    private Integer age;
    private Double score;

    Student(Integer id, String name, Integer age, Double score){
        this.id = id;
        this.name = name;
        this.age = age;
        this.score = score;
    }

}

1.创建一个Stream

default Stream stream() : 返回一个顺序流
default Stream parallelStream() : 返回一个并行流

通过集合创建Stream

public class StreamTest {

    public static List<Student> getStudents() {
        List<Student> students = new ArrayList<>();
        students.add(new Student(1, "小李", 10, 90.0));
        students.add(new Student(2, "小张", 12, 95.0));
        students.add(new Student(3, "小王", 15, 85.0));

        return students;
    }


    public static void main(String[] args) {

        //返回一个顺序流
        Stream<Student> stream1 = getStudents().stream();
        //返回一个并行流
        Stream<Student> stream2 = getStudents().parallelStream();

    }
}

通过数组创建Stream

int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7};
IntStream intStream = Arrays.stream(arr);

备注:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)

通过Stream.of

Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
Stream<String> stringStream = Stream.of("1", "2", "3", "4", "5", "6");
Stream<Student> studentStream = Stream.of(new Student(1, "小李", 10, 90.0), 
          new Student(2, "小张", 12, 95.0), 
          new Student(3, "小王", 15, 85.0));

备注:
public static Stream of(T… values) : 返回一个流

创建一个无限流

//每隔5个数取一个,从0开始,无限循环
Stream.iterate(0, t -> t+5).forEach(System.out::println);
//每隔5个数取一个,从0开始,只取5个数
Stream.iterate(0, t -> t+5).limit(5).forEach(System.out::println);
//取一个随机数
Stream.generate(Math::random).limit(5).forEach(System.out::println);

2.Stream的中间操作

筛选和切片

//过滤:过滤年龄大于12岁的同学
getStudents().stream().filter(item -> item.getAge() > 12).forEach(System.out::println);
//截断流:筛选出前2的同学
getStudents().stream().limit(2).forEach(System.out::println);
//跳过元素:跳过前2的元素
getStudents().stream().skip(2).forEach(System.out::println);
//过滤重复元素
getStudents().stream().distinct().forEach(System.out::println);

映射

//map操作
List<String> list = Arrays.asList("java", "python", "c++");
Stream<String> stream = list.stream();
//此时每一个小写字母都有一个大写字母映射
stream.map(str -> str.toUpperCase()).forEach(System.out::println);

//筛选出所有年龄,再过滤年龄大于12的同学
Stream<Student> stream = getStudents().stream();
Stream<Integer> ageStream = stream.map(Student::getAge);
ageStream.filter(age -> age > 12).forEach(System.out::println);

排序

//自然排序
List<Integer> list = Arrays.asList(1, 3,24, 5, 6, 8, 23, 45, 72, 16);
Stream<Integer> stream = list.stream();
stream.sorted().forEach(System.out::println);

//对象排序:对象排序可以先实现comparable接口,或者直接指定
List<Student> studentList = getStudents();
//实现comparable接口
studentList.stream().sorted().forEach(System.out::println);
//直接指定
studentList.stream().sorted((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())).forEach(System.out::println);

List<String> list = Arrays.asList("c", "e", "a", "d", "b");
list.stream().sorted((s1, s2) -> s1.compareTo(s2)).forEach(System.out::println);

3.Stream的终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、 Integer,甚至是 void 。

匹配和查找

List<Student> list = getStudents();

//判断所有学生年龄是否都大于12岁
boolean allMatch = list.stream().allMatch(item -> item.getAge() > 12);
//判断是否存在学生的年龄大于12岁
boolean anyMatch = list.stream().anyMatch(item -> item.getAge() > 20);
//判断是否有学生叫"小李"
boolean noneMatch = list.stream().noneMatch(item -> item.getName().equals("小李"));
//查找第一个学生
Optional<Student> first = list.stream().findFirst();
//查找学生数据
long count = list.stream().count();
long count1 = list.stream().filter(item -> item.getScore() > 90).count();
//查找当前流中的元素
Optional<Student> any = list.stream().findAny();
//查找学生最高的分数:Student实现了comparable接口的话,可以直接比较
Stream<Double> doubleStream = list.stream().map(item -> item.getScore());
doubleStream.max(Double::compareTo);

归约

List<Integer> list = Arrays.asList(1, 3,24, 5, 6, 8, 23, 45, 72, 16);

//计算总数之和
list.stream().reduce(0, Integer::sum);
//计算学生总分
List<Student> students = getStudents();
Stream<Double> stream = students.stream().map(Student::getScore);
stream.reduce(Double::sum);


Stream<String> stream = Stream.of("you", "give", "me", "stop");
// Optional<T> reduce(BinaryOperator<T> accumulator);
Optional<String> optional = stream.reduce((before, after) -> before + "," + after);
optional.ifPresent(System.out::println);    // you,give,me,stop

输出:
you,give,me,stop

收集

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

//返回一个list
List<Student> list = getStudents().stream().filter(e -> e.getAge() > 12).collect(Collectors.toList());
//返回一个set
Set<Student> set  = getStudents().stream().filter(e -> e.getAge() > 12).collect(Collectors.toSet());


List<Integer> a = Arrays.asList(1, 2, 3);
List<Integer> b = Arrays.asList(4, 5, 6);
List<List<Integer>> collect = Stream.of(a, b).collect(Collectors.toList());
collect.stream().forEach(System.out::println);
输出:
[1, 2, 3]
[4, 5, 6]


List<Integer> a = Arrays.asList(1, 2, 3);
List<Integer> b = Arrays.asList(4, 5, 6);
// 将多个集合中的元素合并成一个集合
List<Integer> mergeList = Stream.of(a, b).flatMap(list -> list.stream()).collect(Collectors.toList());
// [1, 2, 3, 4, 5, 6]
System.out.println(mergeList);

// 通过Builder模式来构建
Stream<Object> stream = Stream.builder().add("hello").add("hi").add("byebye").build();
输出:
[1, 2, 3, 4, 5, 6]


List<String> list = Arrays.asList("1", "2", "3", "4", "5");
// Optional<T> min(Comparator<? super T> comparator);
Optional<String> optional = list.stream().min((a, b) -> a.compareTo(b));
String value = optional.get();
System.out.println(value);
输出:
1

List<String> list = Arrays.asList("a", "b", "c", "d", "e");
// Stream -> Collection
List<String> collect = list.stream().collect(Collectors.toList());
// Stream -> Object[]
Object[] objects = list.stream().toArray();


List<String> list = Arrays.asList("a", "b");
List<String> list2 = Arrays.asList("c", "d");
Stream<String> concatStream = Stream.concat(list.stream(), list2.stream());
concatStream.forEach(System.out::println);
输出:
a
b
c
d

注意:在数据量小的时候不建议使用,大数据量的时候可以使用。

并行流与串行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过 parallel() 与sequential() 在并行流与顺序流之间进行切换。

1.简单概述

Fork/Join 框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总。

2.Fork/Join 与传统线程池区别

采用 “工作窃取”模式(work-stealing):当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。

相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程的等待时间,提高了性能。

 

基本类型Stream

IntStreamLongStream  DoubleStream 分别表示原始 int 流、 原始 long 流 和 原始 double 流。

这三个原始流类提供了大量的方法用于操作流中的数据,同时提供了相应的静态方法来初始化它们自己。这三个原始流类都在 java.util.stream 命名空间下。

1.IntStream

java.util.stream.IntStream 是一个原始整数值序列 ( sequence ) 。该流提供了许多方法可以对该流中的元素顺序执行或并行执行一些聚合操作,比如 max()  average()

聚合方法

方法 说明
rangeClosed(a,b) 返回子序列 [a,b),左闭又开。意味着包括 b 元素,增长步值为 1
range(a,b) 返回子序列 [a,b),左闭右开,意味着不包括 b
sum 计算所有元素的总和
sorted 排序元素
public class IntStreamDemo {
    public static void main(String[] args) {
        System.out.println("--Using IntStream.rangeClosed--");
        IntStream.rangeClosed(13, 15).map(n->n*n).forEach(s->System.out.print(s +" "));
        System.out.println("\n--Using IntStream.range--");
        IntStream.range(13,15).map(n->n*n).forEach(s->System.out.print(s +" "));
        System.out.println("\n--Sum of range 1 to 10--");
        System.out.print(IntStream.rangeClosed(1,10).sum());
        System.out.println("\n--Sorted number--");
        IntStream.of(13,4,15,2,8).sorted().forEach(s->System.out.print(s +" "));
    }
}

输出:
--Using IntStream.rangeClosed--
169 196 225 
--Using IntStream.range--
169 196 
--Sum of range 1 to 10--
55
--Sorted number--
2 4 8 13 15 

2.LongStream

public class LongStreamDemo {
    public static void main(String[] args) {
        System.out.println("--Using LongStream.rangeClosed--");
        LongStream.rangeClosed(13, 15).map(n->n*n).forEach(s->System.out.print(s +" "));
        System.out.println("\n--Using LongStream.range--");
        LongStream.range(13,15).map(n->n*n).forEach(s->System.out.print(s +" "));
        System.out.println("\n--Sum of range 1 to 10--");
        System.out.print(LongStream.rangeClosed(1,10).sum());
        System.out.println("\n--Sorted number--");
        LongStream.of(13,4,15,2,8).sorted().forEach(s->System.out.print(s +" "));
    }
} 

输出结果:
--Using LongStream.rangeClosed--
169 196 225 
--Using LongStream.range--
169 196 
--Sum of range 1 to 10--
55
--Sorted number--
2 4 8 13 15 

3.DoubleStream

java.util.stream.LongStream 是一个原始双精度浮点型序列 ( sequence ) 。该流提供了许多方法可以对该流中的元素顺序执行或并行执行一些聚合操作。

 

public class DoubleStreamDemo {
    public static void main(String[] args) {
        System.out.println("--Using DoubleStream.of--");
        DoubleStream.of(5.33,2.34,5.32,2.31,3.51).map(d->d*1.5).forEach(s->System.out.print(s +" "));
        System.out.println("\n--Using DoubleStream.average--");
        double val = DoubleStream.of(12.1,11.2,13.3).average().getAsDouble();
        System.out.println(val);
        System.out.println("--Using DoubleStream.max--");
        val = DoubleStream.of(12.1,11.2,13.3).max().getAsDouble();
        System.out.println(val);
        System.out.println("--Using DoubleStream.filter--");
        DoublePredicate range = d -> d > 12.11 && d < 12.99;        
        DoubleStream.of(12.1,11.2,12.3).filter(range).forEach(d->System.out.print(d));
    }
}

输出结果:
--Using DoubleStream.of--
7.995 3.51 7.98 3.465 5.265 
--Using DoubleStream.average--
12.200000000000001
--Using DoubleStream.max--
13.3
--Using DoubleStream.filter--
12.3 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!