​Java Stream 详解
  2HyDHh3MOg71 2023年11月02日 32 0

Stream 详解

什么是流?

流是Java8引入的全新概念,它用来处理集合中的数据,暂且可以把它理解为一种高级集合。众所周知,集合操作非常麻烦,若要对集合进行筛选、投影,需要写大量的代码,而流是以声明的形式操作集合,它就像SQL语句,我们只需告诉流需要对集合进行什么操作,它就会自动进行操作,并将执行结果交给你,无需我们自己手写代码。因此,流的集合操作对我们来说是透明的,我们只需向流下达命令,它就会自动把我们想要的结果给我们。由于操作过程完全由Java处理,因此它可以根据当前硬件环境选择最优的方法处理,我们也无需编写复杂又容易出错的多线程代码了。

流的特点

  1. 只能遍历一次 我们可以把流想象成一条流水线,流水线的源头是我们的数据源(一个集合),数据源中的元素依次被输送到流水线上,我们可以在流水线上对元素进行各种操作。一旦元素走到了流水线的另一头,那么这些元素就被“消费掉了”,我们无法再对这个流进行操作。当然,我们可以从数据源那里再获得一个新的流重新遍历一遍。
  2. 采用内部迭代方式 若要对集合进行处理,则需我们手写处理代码,这就叫做外部迭代。而要对流进行处理,我们只需告诉流我们需要什么结果,处理过程由流自行完成,这就称为内部迭代。

流的操作种类

流的操作分为两种,分别为中间操作和终端操作。

  1. 中间操作 当数据源中的数据上了流水线后,这个过程对数据进行的所有操作都称为“中间操作”。中间操作仍然会返回一个流对象,因此多个中间操作可以串连起来形成一个流水线。
  2. 终端操作 当所有的中间操作完成后,若要将数据从流水线上拿下来,则需要执行终端操作。终端操作将返回一个执行结果,这就是你想要的数据。

流的操作过程

使用流一共需要三步:

  1. 准备一个数据源
  2. 执行中间操作 中间操作可以有多个,它们可以串连起来形成流水线。
  3. 执行终端操作 执行终端操作后本次流结束,你将获得一个执行结果。

Stream 接口一览

list转Stream

List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
        //转Stream
        Stream<Integer> stream = integers.stream();
        //并发处理
        Stream<Integer> integerStream = integers.parallelStream();

转list、collect(转换成集合)

// 转list
Collectors.toList();

// 转set
Collectors.toSet();
<R> R collect(Supplier<R> supplier,
             BiConsumer<R, ? super T> accumulator,
             BiConsumer<R, R> combiner);

<R, A> R collect(Collector<? super T, A, R> collector);

例子:将List转换为Strem,然后再转换List

List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
        //转Stream
        List<Integer> collect = integers.stream().collect(Collectors.toList());

filter(过滤)

filter 函数接收一个Lambda表达式作为参数,该表达式返回boolean,在执行过程中,流将元素逐一输送给filter,并筛选出执行结果为true的元素。

Stream<T> filter(Predicate<? super T> predicate);
List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        //filter
        List<Integer> filterList = integerAry.stream()
                .filter(item -> item>3)
                .collect(Collectors.toList());
        for (Integer i : filterList){
            System.out.println("filter: "+i);
        }

​Java Stream 详解_stream流式处理

map(元素转换)

对流中的每个元素执行一个函数,使得元素转换成另一种类型输出。流会将每一个元素输送给map函数,并执行map中的Lambda表达式,最后将执行结果存入一个新的流中。

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

IntStream mapToInt(ToIntFunction<? super T> mapper);

LongStream mapToLong(ToLongFunction<? super T> mapper);

DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);

例子:获取列表每一个值乘以2

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        //map
        List<Integer> mapColl = integerAry.stream()
                .map(item -> item*2)
                .collect(Collectors.toList());
        for (Integer i : mapColl){
            System.out.println("map: "+i);
        }

结果

​Java Stream 详解_stream流式处理_02

distinct(去除重复,对象需要重写 equals、hashCode)

Stream<T> distinct();

例子

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
  //distinct去重
        List<Integer> distinctList = integerAry.stream()
                .distinct()
                .collect(toList());
        for (Integer i : distinctList){
            System.out.println("distinct: "+i);
        }

结果为:

​Java Stream 详解_stream流式处理_03

sorted(排序)

Stream<T> sorted();

Stream<T> sorted(Comparator<? super T> comparator);
List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        //sorted排序
        List<Integer> sortedList = integerAry.stream()
                .sorted()
                .collect(toList());
        for (Integer i : sortedList){
            System.out.println("sorted: "+i);
        }
        //sorted倒序
        List<Integer> reversesortedList = integerAry.stream()
                .sorted(Comparator.reverseOrder())
                .collect(toList());
        for (Integer i : reversesortedList){
            System.out.println("reversesortedList: "+i);
        }

结果:

​Java Stream 详解_stream流式处理_04

peek(生成新的流:流是单向的,例如用于日志打印)

peek方法接收一个Consumer的入参. 了解λ表达式的应该明白 Consumer的实现类应该只有一个方法,该方法返回类型为void. 它只是对Stream中的元素进行某些操作,但是操作之后的数据并不返回到Stream中,所以Stream中的元素还是原来的元素.

Stream<T> peek(Consumer<? super T> action);
List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        List<Integer> peekList = integerAry.stream()
                .peek(item -> System.out.println("peek: "+(item+2)))
                .collect(toList());
        for (Integer i: peekList){
            System.out.println("peekList: "+ i);
        }

​Java Stream 详解_stream流式处理_05

limit(取前面 n 个元素)

Stream<T> limit(long maxSize);

例子:截取List的前3个元素

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        //limit
        List<Integer> limitList = integerAry.stream()
                .limit(3)
                .collect(toList());
        for (Integer i:limitList){
            System.out.println("limit: "+i);
        }

结果:

​Java Stream 详解_stream流式处理_06

skip(跳过 n 个元素)

Stream<T> skip(long n);

例子:跳过list的前3个元素

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        //skip
        List<Integer> skipList = integerAry.stream()
                .skip(3)
                .collect(toList());
        for (Integer i:skipList){
            System.out.println("skip: "+i);
        }

​Java Stream 详解_stream流式处理_07

forEach(遍历)

void forEach(Consumer<? super T> action);

void forEachOrdered(Consumer<? super T> action);
List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        //foreach
        integerAry.stream()
                .forEach(item-> System.out.println("forEach: "+item));

​Java Stream 详解_stream流式处理_08

toArray(转换成数组)

Object[] toArray();
<A> A[] toArray(IntFunction<A[]> generator);

例子

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        Object[] toArray = integerAry.stream()
                .filter(item -> item > 2)
                .toArray();
        //toArray
        for(Object i:toArray){
            System.out.println("toArray: "+i);
        }

​Java Stream 详解_stream流式处理_09

flatMap(元素转换)

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);

LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);

DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
List<String> list = new ArrayList<String>();
        list.add("I am a boy");
        list.add("I love the girl");
        list.add("But the girl loves another girl");

        //flatMap
        List<Object> flatMapAry = list.stream()
                .map(line -> line.split(" "))//按空格分词每个元素变成了一个String[]数组
                .flatMap(Arrays::stream)//此时一个大流里面包含了一个个小流,我们需要将这些小流合并成一个流。 将小流合并成一个大流:用 flatMap 完成
                .distinct()
                .collect(toList());
        for (Object i: flatMapAry){
            System.out.println("flatMap: "+i);
        }

结果:

​Java Stream 详解_stream流式处理_10

anyMatch是否匹配任一元素

anyMatch用于判断流中是否存在至少一个元素满足指定的条件,这个判断条件通过Lambda表达式传递给anyMatch,执行结果为boolean类型

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        //anyMatch
        boolean b = integerAry.stream()
                .anyMatch(item -> item > 3);
        System.out.println("anyMatch: "+b);

结果为:

​Java Stream 详解_stream流式处理_11

allMatch(是否匹配所有元素)

allMatch用于判断流中的所有元素是否都满足指定条件,这个判断条件通过Lambda表达式传递给anyMatch,执行结果为boolean类型。

查看list是否全部大于0

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
  //anyMatch
        boolean allMatchB = integerAry.stream()
                .allMatch(item -> item > 0);
        System.out.println("allMatch: "+allMatchB);

​Java Stream 详解_stream流式处理_12

noneMatch(是否未匹配所有元素)

noneMatch与allMatch恰恰相反,它用于判断流中的所有元素是否都不满足指定条件:

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        boolean nnotallow= integerAry.stream()
                .noneMatch(item -> item > 0);
        System.out.println("noneMatch: "+noneMatchB);

结果:

​Java Stream 详解_stream流式处理_13

findAny(获取任一元素)

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        //获取任一元素
        Optional<Integer> any = integerAry.stream()
                .findAny();
        if(any.isPresent()){
            System.out.println("findAny: "+ any.get());
        }

结果:

​Java Stream 详解_stream流式处理_14

findFirst(获取第一个元素)

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        Optional<Integer> findFirst = integerAry.stream()
                .findFirst();
        if(findFirst.isPresent()){
            System.out.println("findFirst: "+ findFirst.get());
        }

reduce(结果归并)

T reduce(T identity, BinaryOperator<T> accumulator);

Optional<T> reduce(BinaryOperator<T> accumulator);

<U> U reduce(U identity,
            BiFunction<U, ? super T, U> accumulator,
            BinaryOperator<U> combiner);

归约是将集合中的所有元素经过指定运算,折叠成一个元素输出,如:求最值、平均数等,这些操作都是将一个集合的元素折叠成一个元素输出。

在流中,reduce函数能实现归约。reduce函数接收两个参数:

  1. 初始值
  2. 进行归约操作的Lambda表达式

元素求和:自定义Lambda表达式实现求和

List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        //求和
        Integer reduce = integerAry.stream()
                .reduce(0, Integer::sum);
        System.out.println("reduce::sum "+ reduce);

结果:

​Java Stream 详解_stream流式处理_15

  • reduce的第一个参数表示初试值为0;
  • reduce的第二个参数为需要进行的归约操作,它接收一个拥有两个参数的Lambda表达式,reduce会把流中的元素两两输给Lambda表达式,最后将计算出累加之和。

count(计数)

count()方法返回此流中元素的总数

long count();
List<Integer> integerAry = Arrays.asList(1, 2, 1, 2, 3, 6);
        long count = integerAry.stream()
                .count();
        System.out.println("count: "+count);

结果:

​Java Stream 详解_stream流式处理_16

中间操作和收集操作

操作

类型

返回类型

使用的类型/函数式接口

函数描述符

filter

中间

Stream<T>

Predicate<T>

T -> boolean

distinct

中间

Stream<T>



skip

中间

Stream<T>

long


map

中间

Stream<R>

Function<T, R>

T -> R

flatMap

中间

Stream<R>

Function<T, Stream<R>>

T -> Stream<R>

limit

中间

Stream<T>

long


sorted

中间

Stream<T>

Comparator<T>

(T, T) -> int

anyMatch

终端

boolean

Predicate<T>

T -> boolean

noneMatch

终端

boolean

Predicate<T>

T -> boolean

allMatch

终端

boolean

Predicate<T>

T -> boolean

findAny

终端

Optional<T>



findFirst

终端

Optional<T>



forEach

终端

void

Consumer<T>

T -> void

collect

终端

R

Collector<T, A, R>


reduce

终端

Optional<T>

BinaryOperator<T>

(T, T) -> T

count

终端

long



Optional 干掉空指针

简介

  • 空指针异常是导致Java应用程序失败的最常见原因。
  • 为了解决空指针异常更加优雅,Java8 提供了 Optional 类库。
  • Optional实际上是个容器:它可以保存类型T的值,或者仅仅保存null。
  • Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

代码示例

  1. Optional.of()或者Optional.ofNullable():创建Optional对象,差别在于of不允许参数是null,而ofNullable则无限制。
// 参数不能是null
Optional optional1 = Optional.of(1);
// 参数可以是null
Optional optional2 = Optional.ofNullable(null);
// 参数可以是非null
Optional optional3 = Optional.ofNullable(2);
  1. Optional.empty():所有null包装成的Optional对象
Optional optional1 = Optional.ofNullable(null);
Optional optional2 = Optional.ofNullable(null);

System.out.println(optional1 == optional2);// true
System.out.println(optional1 == Optional.empty());// true

Object o1 = Optional.empty();
Object o2 = Optional.empty();

System.out.println(o1 == o2);// true
  1. isPresent():判断值是否存在
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
// isPresent判断值是否存在
System.out.println(optional1.isPresent() == true);
System.out.println(optional2.isPresent() == false);
  1. ifPresent(Consumer consumer):如果option对象保存的值不是null,则调用consumer对象,否则不调用
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

// 如果不是null,调用Consumer
optional1.ifPresent(new Consumer<Integer>() {
   @Override
   public void accept(Integer t) {
      System.out.println("value is " + t);
   }
});

// null,不调用Consumer
optional2.ifPresent(new Consumer<Integer>() {
   @Override
   public void accept(Integer t) {
      System.out.println("value is " + t);
   }
});
  1. orElse(value):如果optional对象保存的值不是null,则返回原来的值,否则返回value
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
// orElse
System.out.println(optional1.orElse(1000) == 1);// true
System.out.println(optional2.orElse(1000) == 1000);// true
  1. orElseGet(Supplier supplier):功能与orElse一样,只不过orElseGet参数是一个对象
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
System.out.println(optional1.orElseGet(() -> 1000) == 1);//true
System.out.println(optional2.orElseGet(() -> 1000) == 1000);//true
  1. orElseThrow():值不存在则抛出异常,存在则什么不做,有点类似GuavaPrecoditions
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

optional1.orElseThrow(() -> {
   throw new IllegalStateException();
});

try {
   optional2.orElseThrow(() -> {
      throw new IllegalStateException();
   });
} catch (IllegalStateException e) {
   e.printStackTrace();
}
  1. filter(Predicate):判断Optional对象中保存的值是否满足Predicate,并返回新的Optional
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

Optional<Integer> filter1 = optional1.filter((a) -> a == null);
Optional<Integer> filter2 = optional1.filter((a) -> a == 1);
Optional<Integer> filter3 = optional2.filter((a) -> a == null);

System.out.println(filter1.isPresent());// false
System.out.println(filter2.isPresent());// true
System.out.println(filter2.get().intValue() == 1);// true
System.out.println(filter3.isPresent());// false
  1. map(Function):对Optional中保存的值进行函数运算,并返回新的Optional(可以是任何类型)
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);

Optional<String> str1Optional = optional1.map((a) -> "key" + a);
Optional<String> str2Optional = optional2.map((a) -> "key" + a);

System.out.println(str1Optional.get());// key1
System.out.println(str2Optional.isPresent());// false

10.flatMap():功能与map()相似,差别请看如下代码。flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional

Optional<Integer> optional1 = Optional.ofNullable(1);

Optional<Optional<String>> str1Optional = optional1.map((a) -> Optional.of("key" + a));
Optional<String> str2Optional = optional1.flatMap((a) -> Optional.of("key" + a));

System.out.println(str1Optional.get().get());// key1
System.out.println(str2Optional.get());// key1

Optional类的方法

方法

描述

empty

返回一个空的 Optional 实例

filter

如果值存在并且满足提供的断言, 就返回包含该值的 Optional 对象;否则返回一个空的 Optional 对象

map

如果值存在,就对该值执行提供的 mapping 函数调用

flatMap

如果值存在,就对该值执行提供的 mapping 函数调用,返回一个 Optional 类型的值,否则就返 回一个空的 Optional 对象

get

如果该值存在,将该值用 Optional 封装返回,否则抛出一个 NoSuchElementException 异常

ifPresent

如果值存在,就执行使用该值的方法调用,否则什么也不做

isPresent

如果值存在就返回 true,否则返回 false

of

将指定值用 Optional 封装之后返回,如果该值为 null,则抛出一个 NullPointerException 异常

ofNullable

将指定值用 Optional 封装之后返回,如果该值为 null,则返回一个空的 Optional 对象

orElse

如果有值则将其返回,否则返回一个默认值

orElseGet

如果有值则将其返回,否则返回一个由指定的 Supplier 接口生成的值

orElseThrow

如果有值则将其返回,否则抛出一个由指定的 Supplier 接口生成的异常

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
2HyDHh3MOg71