java · 2020-01-01 0

Java8 Stream的使用

一、概述

Stream 关注的是对数据的运算,与CPU打交道;集合关注的是数据的存储,与内存打交道

  • Stream自己不会存储数据
  • Stream不会改变源数据,相反,他们会返回一个持有结果的新Stream
  • Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行

步骤:

  1. 创建Stream,一个数据源(如:集合,数组),获取一个流
  2. 中间操作,一个中间操作链,对数据源的数据进行处理
  3. 终止操作,一旦执行终止操作,就执行中间操作链,并产生结果,之后,不会再被使用

二、创建Strem

1.通过集合

Java8中的Collection接口有stream,paralleStream方法:

  • default Stream<E> stream()              返回一个顺序流
  • default Stream<E> paralleStream()   返回一个并行流
@Test
public void test11() {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    Stream<Integer> stream = list.stream();
    Stream<Integer> integerStream = list.parallelStream();
}

2.通过数组

Arrays有静态方法stream()可以获取数组流:

  • public static IntStream stream(int[] array)
  • public static LongStream stream(long[] array)
  • public static DoubleStream stream(double[] array)
@Test
public void test12() {
    int[] arr = new int[] {1, 2, 3};
    IntStream intStream = Arrays.stream(arr);
}

3.通过Stream的of()

Stream类有静态方法of()可以获取一个流

public static<T> Stream<T> of(T... values)
@Test
public void test13() {
    Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
}

4.创建无限流

可以使用静态方法Stream.iterate()和Stream.generate()创建无限流

public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
public static<T> Stream<T> generate(Supplier<T> s)
@Test
public void test14() {
    Stream<Integer> iterate = Stream.iterate(0, t -> t + 2);
    Stream<Double> generate = Stream.generate(Math::random);
}

三、Stream的中间操作

1.筛选与切片

  • filter(Predicate p)     接受Lambda,从流中筛选某些元素
  • distinct()                   通过流生成元素的hashCode()和equals()去除重复元素
  • limit(long maxSize)  截断流,使其元素不超过给定数量
  • skip(long n)              跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
@Test
public void test21() {
    List<String> list = Arrays.asList("C", "A", "A", "B");
    // 1.filter
    Stream<String> stream = list.stream();
    stream.filter((s) -> s.equals("A")).forEach(System.out::print);
    System.out.println();
    // 2.distinct
    stream = list.stream();
    stream.distinct().forEach(System.out::print);
    System.out.println();
    // 3.limit
    stream = list.stream();
    stream.limit(2).forEach(System.out:: print);
    System.out.println();
    // 4.skip
    stream = list.stream();
    stream.skip(2).forEach(System.out::print);
    System.out.println();
}

结果:

2.映射

  • map(Function f)                                接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
  • mapToDouble(ToDoubleFunction f)  接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
  • mapToInt(ToIntFunction f)                 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
  • mapToLong(ToLongFunction f)         接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
  • flatMap(Function f)                            接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
@Test
public void test22() {
    List<String> list = Arrays.asList("C", "A", "A", "B");
    list.stream().map(str -> str.toLowerCase()).forEach(System.out::print);
}

结果:

3.排序

  • sorted() 产生一个新流,其中按自然顺序排序
  • sorted(Comparator com) 产生一个新流,其中按比较器顺序排序
@Test
public void test23() {
    List<String> list = Arrays.asList("C", "A", "A", "B");
    list.stream().sorted().forEach(System.out::print);
}

结果:

四、Stream的终止操作

1.匹配与查找

  - allMatch(Predicate p)        检查是否匹配所有元素
  - anyMatch(Predicate p)      检查是否至少匹配一个元素
  - noneMatch(Predicate p)    检查是否没有匹配所有元素
  - findFirst()                           返回第一个元素
  - findAny()                            返回当前流中的任意元素
  - count()                               返回流中元素总数
  - max(Comparator c)           返回流中最大值
  - min(Comparator c)            返回流中最小值
  - forEach(Consumer c)        内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代,相反,Stream API使用内部迭代--它帮你把迭代做了)

@Test
public void test31() {
    List<String> list = Arrays.asList("C", "A", "A", "B");
    boolean allMatch = list.stream().allMatch(e -> e.equals("B"));
    System.out.println(allMatch);
    boolean anyMatch = list.stream().anyMatch(e -> e.equals("B"));
    System.out.println(anyMatch);
}

结果:

2.归约

  • reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值,返回T
  • reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值,返回Optional<T>
@Test
public void test32() {
    List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    Integer sum = list.stream().reduce(0, Integer::sum);
    System.out.println(sum);
}

结果:

3.收集

Colletor接口中方法的实现决定了如何对流执行收集的操作(如收集到List,Set,Map)

Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例

  • collect(Collector c)    将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
@Test
public void test33() {
    List<String> list = Arrays.asList("C", "A", "A", "B");
    List<String> resList = list.stream().filter(e -> e.equals("A")).collect(Collectors.toList());
    System.out.println(resList);
}

结果: