06-Stream API 操作篇

这篇文章写Stream API 的使用,各个用例中会大量结合 lambda 表达式,如果 函数式接口 和 lambda表达式 玩得不熟的朋友先看看 01-函数式接口和 lambda 表达式 ,如果对 Stream API 的创建、中间操作、终止操作相关接口不熟悉的朋友先看看 05-Stream API 第一篇

提示: 表格的排版在手机端阅读可能有点乱,表格内容可以尝试手机横屏阅读或者电脑端阅读。

Java常用的内置函数式接口:

函数式接口 参数类型 返回类型 用途
Consumer 消费型接口 T void 对给定的 T 类型的参数,进行操作,
核心方法:void accept(T t);
Supplier 供给型接口 空参 T 获取一个 T 类型的对象
核心方法:T get();
Function<T, R> 函数型接口 T R 对 T 类型的参数进行操作,返回 R 类型的结果
核心方法:R apply(T t);
Predicate 断定型接口 T boolean 判断 T 类型的参数,是否满足某约束,返回 boolean 值
核心方法:boolean test(T t);
BiFunction<T, U, R> T, U R 对类型为 T, U 参数应用操作,
返回 R 类型的结果。
核心方法为 R apply(T t, U u);
UnaryOperator
(Function子接口)
T T 对类型为T的对象进行一元运算,
并返回T类型的结果。
核心方法为T apply(T t);
BinaryOperator
(BiFunction 子接口)
T, T T 对类型为T的对象进行二元运算,
并返回T类型的结果。
核心方法为T apply(T t1, T t2);
BiConsumer<T, U> T, U void 对类型为T, U 参数应用操作。
核心方法为void accept(T t, U u)
ToIntFunction
ToLongFunction
ToDoubleFunction
T int/long/double T 类型的参数,
返回int\long\double 类型的结果,
核心方法为int\long\double applyAsInt(T value);
IntFunction
LongFunction
DoubleFunction
int/long/double R 参数分别为int、long、double 类型的函数,
返回 R 类型的结果,
核心方法: R apply(int\long\double value);

1 Stream 创建 API

Stream创建:可通过 数组、Collction 和 Steam类的静态方法来创建一个Stream实例。

定义 Person ,在下面大部分测试用例用到的实体 Bean:

public class Person {

    //姓名
    private String name;
    //年龄
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
        Person person = (Person) o;
        return getAge() == person.getAge() &&
                Objects.equals(getName(), person.getName());
    }

    @Override
    public int hashCode() {

        return Objects.hash(getName(), getAge());
    }

}

1.1 通过数组创建


    /**
     * 通过数组创建Stream
     */
    @Test
    public void testCreateByArray() {
        int[] nums = new int[]{0, 1, 5, 2, 4, 8, 9};
        Person[] personArray = new Person[]{
                new Person("张三", 24),
                new Person("李四", 29),
                new Person("王五", 22),
                new Person("赵六", 15)
        };
        // Arrays.stream(T[] array) 将指定的数组作为数据源,返回一个顺序流
        IntStream stream = Arrays.stream(nums);
        Stream<Person> personStream = Arrays.stream(personArray);

        //打印 stream 中的元素
        System.out.println("打印 stream 中的元素: ");
        stream.forEach(item -> System.out.print(item + " "));
        //打印 personStream 中的元素
        System.out.println("\n打印 personStream 中的元素: ");
        personStream.forEach(item -> System.out.println(item + " "));
    }

运行结果:

打印 stream 中的元素: 
0 1 5 2 4 8 9 
打印 personStream 中的元素: 
Person{name='张三', age=24} 
Person{name='李四', age=29} 
Person{name='王五', age=22} 
Person{name='赵六', age=15} 

1.2 通过Collection创建

Collection接口中提供了 stream() 获取顺序流和 parallelStream() 获取并行流的两个方法
顺序流:串行流,流中的元素序列顺序和元素在数据源中的顺序是一样的。
并行流:把元素序列分成多个数据块,并用不同的线程分别处理每个数据块的流

Stream API 可以通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。

public class StreamAPITest {
    List<Person> persons = null;

    @Before
    public void before() {
        persons = Arrays.asList(
                new Person("刘一", 25),
                new Person("陈二", 12),
                new Person("张三", 24),
                new Person("李四", 29),
                new Person("王五", 22),
                new Person("赵六", 15),
                new Person("孙七", 16),
                new Person("周八", 18)
        );
    }
    
    /**
     * 通过Collection创建Stream
     */
    @Test
    public void testCreateByCollection() {
        //stream() 将此集合作为数据源,返回一个顺序流
        Stream<Person> seqStream = persons.stream();
        //parallelStream() 将此集合作为数据源,返回一个并行流
        Stream<Person> parallelStream = persons.parallelStream();


        //打印顺序流 seqStream 中的元素
        System.out.println("打印顺序流 seqStream 中的元素: ");
        seqStream.forEach(item -> System.out.println("线程名" + Thread.currentThread().getName() + "--" + item + " "));


        //并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流
        // 打印并行流 parallelStream 中的元素,并行输出,输出结果是无序的
        System.out.println("\n打印并行流 parallelStream 中的元素,并行输出,输出结果是无序的: ");
        parallelStream.forEach(item -> System.out.println("线程名" + Thread.currentThread().getName() + "--" + item + " "));

        System.out.println("\nsequential()把并行流切换成顺序流,输出: ");
        persons.parallelStream()
                .sequential()//并行流切换成顺序流
                .forEach(item -> System.out.println("线程名" + Thread.currentThread().getName() + "--" + item + " "));
    }

}

运行结果:

打印顺序流 seqStream 中的元素: 
线程名main--Person{name='刘一', age=25} 
线程名main--Person{name='陈二', age=12} 
线程名main--Person{name='张三', age=24} 
线程名main--Person{name='李四', age=29} 
线程名main--Person{name='王五', age=22} 
线程名main--Person{name='赵六', age=15} 
线程名main--Person{name='孙七', age=16} 
线程名main--Person{name='周八', age=18} 

打印并行流 parallelStream 中的元素,并行输出,输出结果是无序的: 
线程名main--Person{name='赵六', age=15} 
线程名main--Person{name='王五', age=22} 
线程名main--Person{name='周八', age=18} 
线程名main--Person{name='孙七', age=16} 
线程名ForkJoinPool.commonPool-worker-11--Person{name='李四', age=29} 
线程名ForkJoinPool.commonPool-worker-9--Person{name='张三', age=24} 
线程名ForkJoinPool.commonPool-worker-2--Person{name='陈二', age=12} 
线程名ForkJoinPool.commonPool-worker-9--Person{name='刘一', age=25} 

sequential()把并行流切换成顺序流,输出: 
线程名main--Person{name='刘一', age=25} 
线程名main--Person{name='陈二', age=12} 
线程名main--Person{name='张三', age=24} 
线程名main--Person{name='李四', age=29} 
线程名main--Person{name='王五', age=22} 
线程名main--Person{name='赵六', age=15} 
线程名main--Person{name='孙七', age=16} 
线程名main--Person{name='周八', age=18} 

1.3 通过Stream的静态方法创建Stream

Stream接口提供了几个静态方法可以创建一个Stream实例,常用的是:of()、iterate()、generate()


    /**
     * 通过Stream的静态方法创建Stream
     */
    @Test
    public void testCreateByStaticMethod() {
        // 将参数数组作为数据源,返回一个顺序流,底层调用的是Arrays.stream(T[] array)
        Stream<Integer> of = Stream.of(0, 1, 5, 2, 4, 8, 9);// 不断产生 0,2,4,6,8,10.,...,n,n+2
        System.out.println("of() 将参数数组作为数据源,返回一个顺序流: ");
        of.forEach(item -> System.out.print(item + " "));

        // 创建无限流,入参是初始元素和UnaryOperator函数式接口,返回一个有规律的无限顺序流
        Stream<Integer> iterate = Stream.iterate(0, n -> n + 2);// 不断产生 0,2,4,6,8,10.,...,n,n+2
        System.out.println("\n\niterate() 返回一个有规律的无限顺序流,限制输出前10个: ");
        iterate.limit(10).forEach(item -> System.out.print(item + " "));
        // 创建无限流,入参是Supplier,返回一个无规律的无限顺序流,其中每个元素由提供的Supplier生成,适用于生成恒定流、随机元素流
        Stream<Integer> generate = Stream.generate(() -> (int) (Math.random() * 10));// 不断产生 0-9 的随机数
        System.out.println("\n\ngenerate() 返回一个有规律的无限顺序流,限制输出前10个: ");
        generate.limit(10).forEach(item -> System.out.print(item + " "));
    }

运行结果:

of() 将参数数组作为数据源,返回一个顺序流: 
0 1 5 2 4 8 9 

iterate() 返回一个有规律的无限顺序流,限制输出前10个: 
0 2 4 6 8 10 12 14 16 18 

generate() 返回一个有规律的无限顺序流,限制输出前10个: 
2 6 9 2 7 1 4 6 0 0 

2 终止操作

因为 Stream 有惰性求值的特点,中间操作,并不会立即执行,只有触发终止操作时,才会进行实际的运算。

Stream 操作可以有 0个或者多个中间操作,但是 有且只有一个终止操作

所以下面为了方便演示,我们讲解终止操作的使用,再讲解中间操作的使用。

2.1 allMatch

allMatch操作,如果流中所有元素都匹配 predicate 或者是空流,返回true,否则返回false

public class StreamAPITest {
    List<Person> persons = null;

    @Before
    public void before() {
        persons = Arrays.asList(
                new Person("刘一", 25),
                new Person("陈二", 12),
                new Person("张三", 24),
                new Person("李四", 29),
                new Person("王五", 22),
                new Person("赵六", 15),
                new Person("孙七", 16),
                new Person("周八", 18)
        );
    }
    
    /**
     * allMatch操作,如果流中所有元素都匹配 predicate 或者是空流,返回true,否则返回false
     */
    @Test
    public void testStreamAllMatch() {
        Stream<Pe
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值