java之Stream流与方法引用

目录

一张图说明Stream流

常见的操作函数

常见的终结函数

如何创建一个Stream流

 方法引用

具体说说方法引用


一张图说明Stream流

java之Stream流与方法引用_第1张图片

常见的操作函数

首先说明一下,什么是操作函数,就是调用这个函数之后,依然会给我们返回这个流,不会结束

1.filter函数

 内部传入了Predicate函数式接口,里面有一个方法是boolean test(T t),也就是他是一个判断过滤函数,不满足条件的数据流会被踢出去。

2.skip函数

java之Stream流与方法引用_第2张图片

 3.limit函数

        

4.map

   里面传入的是一个Function函数式接口

 它内部的一个方法是apply,把一个数据类型变成另外一个数据类型

Demo3.java

import java.util.stream.Stream;

public class Demo3 {
    public static void main(String[] args) {
        Stream stream1 = Stream.of("10","520","13");
        //这是一个String类型的流,我要变成int类型的流
        Stream res = stream1.map(str->Integer.parseInt(str));
    }
}

5.contact函数

 简单说也就是合并两个流变成一个新流的意思

常见的终结函数

1.count函数

2.foreach函数

里面是一个Consumer接口,它的抽象接口是java之Stream流与方法引用_第3张图片 

接收一个参数进行消费,这个方法一般是对流里面的数据一个打印操作

看一个具体实现代码

Demo1.java

import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.stream.Stream;

public class Demo1 {

    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("张三丰");
        list.add("李四");
        list.add("王五");
        list.add("张君宝");
        list.add("张帅");

        Stream stream1 = list.stream();

        Stream stream2 = stream1.filter(str->str.length() == 3)
                .filter(str->str.startsWith("张"))
                .limit(3);

        ArrayList list1 = new ArrayList();

        stream2.forEach(str-> list1.add(str));

        System.out.println(list1);
    }

}

 运行结果:

java之Stream流与方法引用_第4张图片

如何创建一个Stream流

java之Stream流与方法引用_第5张图片

然后来看代码:

        List one = new ArrayList<>();
        // ...
        List two = new ArrayList<>();
        // ...
        // 第一个队伍只要名字为3个字的成员姓名;
        // 第一个队伍筛选之后只要前3个人;
        Stream streamOne = one.stream().filter(s ‐> s.length() == 3).limit(3);
        // 第二个队伍只要姓张的成员姓名;
        // 第二个队伍筛选之后不要前2个人;
        Stream streamTwo = two.stream().filter(s ‐> s.startsWith("张")).skip(2);
        // 将两个队伍合并为一个队伍;
        // 根据姓名创建Person对象;
        // 打印整个队伍的Person对象信息。
        Stream.concat(streamOne, streamTwo).map(Person::new).forEach(System.out::println);

 方法引用

java之Stream流与方法引用_第6张图片

大致就是:obj::方法

其中类的构造器与数组的构造器引用如下使用:

类::new

int[]::new 

下面说一下方法引用的可推导原则:

java之Stream流与方法引用_第7张图片

具体说说方法引用

1.方法引用的前提:

        函数式接口

为啥是函数式接口呢?因为方法引用本质就是,调用了一个已经实现了函数式接口的方法。

2.方法引用的参数:

        无参数

为啥说无参数,因为调用了一个已经存在了的方法,别人已经把参数做好了,你还要啥参数,只需要这个方法匹配就可以了。可推导就是可省略嘛

3.看几个实例

        3.1通过对象名引入成员方法

        函数式接口AddInterface.java

package pxx;

public interface AddInterface {
    //是不是与对象里面的一个方法对应了呢,与Demo1里面的饿方法
    int add(int num1,int num2);
}

        上一个对象,其实就是实现了函数式接口里面的方法

        Demo1.java

package pxx;

public class Demo1 {
    //对象名要引入这个方法对吗?
    //做一个函数式接口的一个实现
    public int add(int num1,int num2) {
        return num1 + num2;
    }
}

然后测试类Demo2.java

package pxx;

public class Demo2 {
    //这里也就是说,要调用函数式接口对吧
    public static int calcRes(int num1,int num2,AddInterface addInterface) {
        return addInterface.add(num1,num2);
    }

    public static void main(String[] args) {
        Demo1 demo1 = new Demo1();
        //lambda表达式可以不,这样绝对可以,但是有点麻烦
        int res = calcRes(1,2,(num1,num2)->num1+num2);
        //我就用方法引用,存了已经实现了好了的函数式接口方法,为何不用
        int res1 = calcRes(1,2,demo1::add);
        System.out.println(res + " " + res1);
    }
}

运行结果:

java之Stream流与方法引用_第8张图片

其他类似。 

具体再说一下对象引用与类的构造器引用 

 

package com.pxx.functionInterface;

import java.util.stream.Stream;

class Person {
    private String name;

    public Person() {
        this.name = "unknown";
    }

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

public class Demo1 {
    public static void main(String[] args) {
        //创建两个字符串流
        Stream streamOne = Stream.of("aa","bb","cc");

        //函数传入参数适用于可推导原则
        //比如Person::new这里就是类的构造器引用
        //这里的推导原则就是:他符不符合当前内部函数式接口的实现
        //比如Person::new -> 它的构造方法是一个有参的构造函数 public Person(String name)
        //通过这个函数,我们传入一个name,会给我们返回一个Person对象
        //而在map方法里面是一个Function函数式接口
        //R apply(T t)把T类型变成R类型是不是和上面构造方法是一个方式
        //所以,可以通过类的构造器引用进行一个函数式接口的实现
        //------------------------------
        //再来看一下forEach,它也是Stream流里面的方法
        //它内部的函数式接口是forEach(Consumer action)
        //Consumer是一个消费式的函数式接口,也就是接收一个参数,然后把这个参数用来干嘛无返回值
        //这里System.out就是一个对象吗,它是一个标准输出流对象PrintStream
        //它内部的一个println方法就是接收一个参数,然后内部进行操作,无返回值
        //这里就是对象引用
        streamOne.map(Person::new).forEach(System.out::println);
    }
}

这里我在来引入一个问题就是,当我们使用类的构造器引入一个构造方法的时候,到底是用调用的有参构造还是无参构造方法,这里就涉及到了一个“目标类型的推断”。

根据实际场景会自动选择合适的构造函数

package com.pxx.functionInterface;

import java.util.stream.Stream;

class Person1 {
    private String name;

    public Person1() {
        this.name = "unknown";
    }

    public Person1(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person1{" +
                "name='" + name + '\'' +
                '}';
    }
}


public class Demo2 {
    public static void main(String[] args) {
        //这里利用generate生成一个无限流,就是这个流里面会有很多的数据
        //(Supplier s) 它是一个生产式的接口,没有参数,需要范返回值
        //这里调用无参,为什么调用无参,就是因为generate里面就是无参的函数式接口
        Stream.generate(Person::new).limit(5).forEach(System.out::println);
    }
}

java之Stream流与方法引用_第9张图片

你可能感兴趣的:(java基础,java,开发语言,后端)