Stream流基本使用指南

简介: Stream流基本使用指南

Stream流

1.Sream流概述

我们可以把集合|数组,转换为Stream流,使用Stream流中的方法,对集合|数组进行操作

2.流式思想概述

1594190022116.png

3.获取Stream流的方式

  • 使用Collection接口中,(jdk1.8之后)定义了一个方法stream,可以把集合转换为Stream流

    default Stream<E> stream()         // 此转换方法只能是Collection接口下的集合使用
  • 使用Stream接口中方法of,可以把可变参数(数组)转换为Stream流

    java.util.stream.Stream 接口(jdk1.8之后)

    static <T> Stream<T> of(T... values)     // 方法的参数是一个可变参数,也可以传递数组
import java.util.*;
import java.util.stream.Stream;

public class Demo03Stream {
    public static void main(String[] args) {
        show02();
    }

    /*
        把数组转换为Stream流
        注意:
            看到的方法参数是一个可变参数,那么就可以传递数组,因为可变参数底层就是一个数组
            static <T> Stream<T> of (T... values) :方法的参数是一个可变参数,也可以传递数组
     */
    private static void show02() {
        Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
        Stream<String> stream2 = Stream.of("a", "b", "c");

        String[] arr1 = {"a", "b", "c"};
        Stream<String> stream3 = Stream.of(arr1);
        //注意:数组的数组类型必须是包装类,不要使用基本数据类型
        int[] arr2 = {1,2,3};
        Stream<int[]> stream4 = Stream.of(arr2);
        System.out.println(stream4.count());//1 把数组作为一个元素,转换为Stream流

        Integer[] arr3 = {1,2,3};
        Stream<Integer> stream5 = Stream.of(arr3);
        System.out.println(stream5.count());//3
    }

    /*
        把集合转换为Stream流
     */
    private static void show01() {
        ArrayList<Integer> list = new ArrayList<>();
        Stream<Integer> stream1 = list.stream();

        LinkedList<String> linked = new LinkedList<>();
        Stream<String> stream2 = linked.stream();

        HashSet<Integer> set = new HashSet<>();
        Stream<Integer> stream3 = set.stream();

        HashMap<String,String> map = new HashMap<>();
        //map.stream();//Cannot resolve method 'stream()' Map集合不能直接转换为Stream流

        //获取Map集合中所有的key
        Set<String> keySet = map.keySet();
        Stream<String> stream4 = keySet.stream();

        //获取Map集合中所有的value
        Collection<String> values = map.values();
        Stream<String> stream5 = values.stream();

        //获取Map集合中所有的Entry对象
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        Stream<Map.Entry<String, String>> stream6 = entrySet.stream();
    }
}

4.Stream的常用方法

流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

  • 终结方法:返回值类型不再是Stream接口自身类型的方法,因此不再支持类似StringBuilder那样的链式调用。本小节中,终结方法包括countforEach方法。
  • 非终结方法:返回值类型仍然是Stream接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为非终结方法。)

函数拼接与终结方法

在上述介绍的各种方法中,凡是返回值仍然为Stream接口的为函数拼接方法,它们支持链式调用;而返回值不再为Stream接口的为终结方法,不再支持链式调用。如下表所示:

方法名 方法作用 方法种类 是否支持链式调用
filter 过滤 函数拼接
limit 取用前几个 函数拼接
skip 跳过前几个 函数拼接
map 映射 函数拼接
concat 组合 函数拼接
count 统计个数 终结
forEach 逐一处理 终结
备注:本小节之外的更多方法,请自行参考API文档。

forEach 方法:用于遍历

void forEach(Consumer<? super T> action)     // 对此流的每个元素执行操作。

// 参数:
//        Consumer<? super T> action:是一个消费型的接口,参数可以传递Lambda表达式
//        唯一的抽象方法:void accept(T t) 消费一个指定泛型类型的数据

注意:

forEach方法是一个终结方法,没有返回值;也不能使用链式编程调用Stream流中的其他方法了

import java.util.stream.Stream;

public class Demo04forEach {
    public static void main(String[] args) {
        //获取Stream流
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        //使用forEach方法遍历Stream流中的元素
        /*stream.forEach((Integer i)->{
            System.out.println(i);
        });*/

        /*
            IllegalStateException: stream has already been operated upon or closed
            Stream流对象只能使用一次,使用完毕就会流向下一个对象
            之前的Stream流对象就已经关闭了,被销毁了,所以就不能在使用了,会抛出非法状态异常
            简化lambda表达式
         */
        stream.forEach(i-> System.out.println(i));
    }
}

count 方法:统计个数

long count()     // 返回此流中的元素数。

注意:count方法是一个终结方法,返回值类型是long类型;也不能使用链式编程调用Stream流中的其他方法了

import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Stream;

public class Demo05count {
    public static void main(String[] args) {
        //获取Stream流
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        long c1 = stream.count();
        System.out.println(c1);//10

        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"aa","bb","cc","dd","ee");
        //把集合转换为Stream流
        Stream<String> stream2 = list.stream();
        System.out.println(stream2.count());//5
    }
}

filter 方法:过滤元素

Stream<T> filter(Predicate<? super T> predicate)
//    参数:
//         Predicate<? super T> predicate:函数式接口,参数传递lambda表达式
//        唯一的抽象方法:boolean test(T t) 用于对接口指定泛型类型的数据进行判断

注意:filter方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)

import java.util.stream.Stream;

public class Demo06filter {
    public static void main(String[] args) {
        //创建一个Stream流
        Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "懒羊羊", "沸羊羊", "暖羊羊", "慢羊羊", "灰太狼", "红太狼", "小灰灰");
        //使用filter方法过滤Stream流中的元素,只要包含羊羊的
       //Stream<String> stream2 = stream.filter((String s) -> {
       //    return s.contains("羊羊");
       //});
        //遍历stream2流对象
        //stream2.forEach(s-> System.out.println(s));

        //链式编程
        stream.filter(s->s.contains("羊羊")).forEach(s-> System.out.println(s));
    }
}

limit 方法:获取前n个元素

Stream<T> limit(long maxSize)     // 返回由此流的元素组成的流,截短长度不能超过 maxSize 。
// 例如:limit(4);获取流中的前4个元素,把4个元素存储到一个新的Steam流中

注意:

1.传递数字大于流的长度,返回流中所有的元素

2.limit方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)

import java.util.stream.Stream;

public class Demo07limit {
    public static void main(String[] args) {
        //创建一个Stream流
        Stream<String> stream = Stream.of("美羊羊", "喜羊羊", "懒羊羊", "沸羊羊", "暖羊羊", "慢羊羊", "灰太狼", "红太狼", "小灰灰");
        //获取Stream流中的前4个元素,存储到一个新的Stream流中返回
        //Stream<String> stream2 = stream.limit(4);
        //stream2.forEach(s-> System.out.println(s));

        //stream.limit(4).forEach(s-> System.out.println(s));
        stream.limit(10).forEach(s-> System.out.println(s));//9个
    }
}

skip 方法:跳过前n个元素

 Stream<T> skip(long n)

注意:

1.skip跳过的元素数量大于流中的个数,返回一个没有元素的空流

2.skip方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)

import java.util.stream.Stream;

public class Demo08skip {
    public static void main(String[] args) {
        //获取Stream流
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        //跳过前6个元素,把剩余的元素,存储到一个新的Stream流中返回
        //Stream<Integer> stream2 = stream.skip(6);
        //stream2.forEach(s-> System.out.println(s));

        //stream.skip(6).forEach(s-> System.out.println(s));
        //stream.skip(11).forEach(s-> System.out.println(s));
        System.out.println(stream.skip(11).count());//0 skip跳过的元素数量大于流中的个数,返回一个没有元素的空流
    }
}

map 方法:映射,类型转换

<R> Stream<R> map​(Function<T,R> mapper)
//    参数:
//        Function<T,R> mapper:函数式接口,可以传递Lambda表达式
//        接口中唯一的抽象方法:R apply(T t) 根据参数类型T获取类型R类型的返回值,用于类型转换 T转换R

注意:

map方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)

import java.util.stream.Stream;

public class Demo09map {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("11", "22", "33", "44");
        //使用map方法,把字符串类型的Stream流,转换为Integer类型的Stream流返回
        //Stream<Integer> stream2 = stream.map((String s) -> {
        //    return Integer.parseInt(s);
        //});
        //遍历stream2流对象
        //stream2.forEach(s-> System.out.println(s+10));

        stream.map(s->Integer.parseInt(s)).forEach(s-> System.out.println(s));

        Stream<String> stream3 = Stream.of("迪丽热巴", "杨幂", "柳岩");
        //使用map方法,把字符串类型的Stream流,转换为Person类型的流返回
        //Stream<Person> stream4 = stream3.map(s -> new Person(s));
        //stream4.forEach(s-> System.out.println(s));

        stream3.map(s->new Person(s)).forEach(p-> System.out.println(p));
    }
}

concat 方法:组合

// 把两个Stream流,组合为一个新的Stream流
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)

注意:

concat方法的返回值类型还是Stream类型,是一个非终结方法,可以使用返回的Stream对象继续调用Stream流中的方法(链式编程)

import java.io.Serializable;
import java.util.stream.Stream;

public class Demo10concat {
    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("美羊羊", "喜羊羊", "懒羊羊", "沸羊羊", "暖羊羊", "慢羊羊", "灰太狼", "红太狼", "小灰灰");
        Stream<String> stream2 = Stream.of("迪丽热巴", "杨幂", "柳岩");

        //使用concat方法,把stream1和stream2组合为一个新的流
        //Stream<String> concat = Stream.concat(stream1, stream2);
        //遍历Stream流
        //concat.forEach(s-> System.out.println(s));

        Stream.concat(stream1, stream2).forEach(s-> System.out.println(s));

        Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Stream<String> stream4 = Stream.of("11", "22", "33", "44");
        Stream<Object> stream5 = Stream.concat(stream3, stream4);
        stream5.forEach(s-> System.out.println(s));
    }
}

sorted 方法:排序

Stream<T> sorted(Comparator<? super T> comparator)

flatMap 方法:维度升降

参考:https://blog.csdn.net/dengjili/article/details/90557392

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

可以将 Stream<Stream> 升维成 Stream,从而实现将 List<List> 里的对象集合快速合并为 List

    @Test
    public void test(){
        Map<String, ArrayList<TestVo>> map = Maps.newHashMap("1",
            Lists.newArrayList(TestVo.builder().data("3").build(), TestVo.builder().data("1").build()));
        map.put("0", Lists.newArrayList(TestVo.builder().data("8").build()));
        map.put("3", Lists.newArrayList(TestVo.builder().data("2").build()));

        List<TestBaseVo> list = map.entrySet().stream()
            .map(s -> s.getValue().stream()
                .sorted(Comparator.comparing(TestVo::getData))
                .map(t -> TestBaseVo.builder().clazz(t.getData()).build()))
            .flatMap(a -> a)
            .collect(Collectors.toList());
        System.out.println(list);
    }

5.收集Stream结果(重点)

把Stream流转换为集合或者把Stream流转换为数组

1).把Stream流转换为集合

使用Stream流中的方法:

R collect(Collector<?> collector)     //把Stream流转换为集合
// 参数:Collector是一个接口,需要传递接口的实现类对象

java.util.stream.Collectors:是一个工具类,里边提供的静态的方法,可以获取Collector接口的实现类对象

static <T> Collector<T, ?, List<T>> toList()     // 返回一个 Collector ,将输入元素累加到一个新的 List
static <T> Collector<T, ?, Set<T>> toSet()         // 返回一个 Collector ,将输入元素累加到一个新的 Set
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
    Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Demo01StreamToCollection {
    public static void main(String[] args) {
        //创建一个Stream流
        Stream<String> stream = Stream.of("美羊羊", "喜羊羊",
                "懒羊羊", "沸羊羊", "暖羊羊", "慢羊羊", "灰太狼", "红太狼", "小灰灰", "灰太狼");

        //把Stream流转换为List集合(有序,有索引,允许重复)
        //List<String> list = stream.collect(Collectors.toList());
        //System.out.println(list);//[美羊羊, 喜羊羊, 懒羊羊, 沸羊羊, 暖羊羊, 慢羊羊, 灰太狼, 红太狼, 小灰灰, 灰太狼]

        //把Stream流转换为Set集合(不包含带索引的方法,不允许存储重复的元素)
        Set<String> set = stream.collect(Collectors.toSet());
        System.out.println(set);//[美羊羊, 沸羊羊, 红太狼, 灰太狼, 暖羊羊, 小灰灰, 喜羊羊, 懒羊羊, 慢羊羊]
    }
}

2).把Stream流转换为数组

Stream流中的方法:

Object[] toArray()         // 返回一个包含此流的元素的数组。
import java.util.stream.Stream;

public class Demo02StreamToArray {
    public static void main(String[] args) {
        //创建一个Stream流
        Stream<String> stream = Stream.of("美羊羊", "喜羊羊",
                "懒羊羊", "沸羊羊", "暖羊羊", "慢羊羊", "灰太狼", "红太狼", "小灰灰", "灰太狼");

        Object[] arr = stream.toArray();
        for (Object o : arr) {
            System.out.println(o);
        }
    }
}
相关文章
|
6月前
|
Java API 数据处理
探索 Java 8 中的 Stream 流:构建流的多种方式
探索 Java 8 中的 Stream 流:构建流的多种方式
|
6月前
|
Java
【Java】Stream流是什么,如何使用Stream流?
【Java】Stream流是什么,如何使用Stream流?
82 0
|
2月前
|
Java 数据处理
Stream流的简单使用
这篇文章介绍了Java中Stream流的基本概念和使用方法。文章解释了Stream流的三类方法:获取流、中间方法和终结方法。详细讨论了如何生成Stream流,包括从Collection体系集合、Map体系集合、数组和同种数据类型的多个数据中生成流。接着,介绍了Stream流的中间操作方法,如`filter`、`limit`、`skip`、`concat`和`distinct`。文章还讨论了Stream流的终结方法,如`forEach`和`count`,以及收集方法,如`collect`。最后,通过几个例子演示了如何使用Stream流进行数据处理和收集操作。
|
6月前
|
存储 Java API
Stream流
Stream流
63 1
|
4月前
|
存储 Java BI
Java基础之stream流最新版,stream流的基本操作
Java基础之stream流最新版,stream流的基本操作
57 0
|
6月前
|
Java 容器
Stream 流常见基本操作
Stream 流常见基本操作
|
5月前
|
存储 Java API
Java——Stream流(1/2):Stream流入门、Stream流的创建(认识Stream、体验Stream流、Stream流的使用步骤、获取Stream流的方法)
Java——Stream流(1/2):Stream流入门、Stream流的创建(认识Stream、体验Stream流、Stream流的使用步骤、获取Stream流的方法)
80 0
|
5月前
|
API
Stream流知识
Stream流知识
30 0
|
6月前
|
Java
Stream流教程
Stream流教程
68 0
|
6月前
|
SQL JavaScript Java
Stream 的使用,我觉得使用它是非常方便的~
Stream 的使用,我觉得使用它是非常方便的~
48 0