函数式接口与Stream流计算

一:函数型接口

函数式接口泛指那些在有且仅有一个抽象方法的接口,其标志特点是源码中含有@FunctionalInterface注解。

名称 定位
Function 函数型接口
Predicate 断定型接口
Consumer 消费型接口
Supplier 供给型接口



1.函数型接口(Function )

函数式接口与Stream流计算_第1张图片
Function,T是一个传入的参数类型,R是一个返回的参数类型,函数式接口只有一个抽象方法,在这里是apply,apply方法有返回值,其类型是R。

 		//函数式接口Function
        Function<String,Boolean> function = (str)->{
            return  str.isEmpty();
        };
        System.out.println("函数式接口Function  "+function.apply("adasdasd"));

打印结果:

函数式接口Function  false



2.断定式接口(Predicate)

函数式接口与Stream流计算_第2张图片

Predicate< T>只有一个用户的传入类型T,唯一的一个抽象方法为test,其固定返回类型为Boolean。

  //断定式接口Predicate,返回只能是布尔
       Predicate<Integer> predicate = (nu)->{
           return nu>0;
       };
        System.out.println("函数式接口Predicate"+predicate.test(20));

运行结果:

函数式接口Predicate true



3.消费型接口(Consumer)

函数式接口与Stream流计算_第3张图片Consumer< T>,唯一指定参数T,唯一抽象方法为accept,无返回值。

	//消费型接口
        Consumer<String> consumer = (c1)->{
            System.out.println(c1);
        };
        consumer.accept("消费型接口");

运行结果:

消费型接口



4.供给型接口(Supplier)

函数式接口与Stream流计算_第4张图片Supplier< T>唯一指定参数类型T,唯一抽象方法为get(),其返回类型为手动指定的T。

        //供给型接口
        Supplier<String> supplier = ()->{
            return "gety";
        };
        System.out.println(supplier.get());

运行结果:

gety





二:Stream流计算


1.存在一个User实体类:

package Stream;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private  Integer id;
    private String name;
    private  Integer age;

}

2.在测试类中连续声明对应的五个实体类

		User user1 = new User(1,"a",23);
        User user2 = new User(2,"b",21);
        User user3 = new User(3,"c",29);
        User user4 = new User(4,"d",22);
        User user5 = new User(5,"e",18);

问题1:输出id为偶数的User

    public void test2(){
        User user1 = new User(1,"a",23);
        User user2 = new User(2,"b",21);
        User user3 = new User(3,"c",29);
        User user4 = new User(4,"d",22);
        User user5 = new User(5,"e",18);

        List<User> list = Arrays.asList(user1,user2,user3,user4,user5);
        
        //用流来计算
        list.stream()
                .filter(user -> {return user.getId()%2==0;})
                .forEach(System.out::println);


    }

运行结果:

User(id=2, name=b, age=21)
User(id=4, name=d, age=22)

其中,.stream()是生成流,而具体的.filter中之所以可以填一个lambada表达式,是因为.filter的底层就是一个断定型接口。
函数式接口与Stream流计算_第5张图片



问题2:继续在问题1的基础上输出年龄大于21岁的用户

    public void test2(){
        User user1 = new User(1,"a",23);
        User user2 = new User(2,"b",21);
        User user3 = new User(3,"c",29);
        User user4 = new User(4,"d",22);
        User user5 = new User(5,"e",18);

        List<User> list = Arrays.asList(user1,user2,user3,user4,user5);
        
        //用流来计算
        list.stream()
                .filter(user -> {return user.getId()%2==0;})
                .filter(user -> {return user.getAge()>21;})
                .forEach(System.out::println);


    }

运行结果:

User(id=4, name=d, age=22)





问题3:在上一个问题的基础上将用户名大写输出

    public void test2(){
        User user1 = new User(1,"a",23);
        User user2 = new User(2,"b",21);
        User user3 = new User(3,"c",29);
        User user4 = new User(4,"d",22);
        User user5 = new User(5,"e",18);

        List<User> list = Arrays.asList(user1,user2,user3,user4,user5);
        
        //用流来计算
         list.stream()
                .filter(user -> {return user.getId()%2==0;})
                .filter(user -> {return user.getAge()>21;})
                .map(user -> {return user.getName().toUpperCase();})
                .forEach(System.out::println);


    }

运行结果:

D

至于这里为什么返回的是一个字符而不是一个User对象,是因为Map底层是一个函数式接口,而函数式接口的T和R可以是两个不同的类型。
函数式接口与Stream流计算_第6张图片第一个参数指定了对象user,但return 的user.getName().toUpperCase()是一个字符串,所以就返回了一个字符串。





问题4:假如最终结果是多个值,我只想输出一个怎么办

改变一下,输出年龄大于20的

    public void test2(){
        User user1 = new User(1,"a",23);
        User user2 = new User(2,"b",21);
        User user3 = new User(3,"c",29);
        User user4 = new User(4,"d",22);
        User user5 = new User(5,"e",18);

        List<User> list = Arrays.asList(user1,user2,user3,user4,user5);
        
        //用流来计算
         list.stream()
                .filter(user -> {return user.getId()%2==0;})
                .filter(user -> {return user.getAge()>20;})
                .map(user -> {return user.getName().toUpperCase();})
                .forEach(System.out::println);


    }

运行结果:

B
D

然后最终只取一个

    public void test2(){
        User user1 = new User(1,"a",23);
        User user2 = new User(2,"b",21);
        User user3 = new User(3,"c",29);
        User user4 = new User(4,"d",22);
        User user5 = new User(5,"e",18);

        List<User> list = Arrays.asList(user1,user2,user3,user4,user5);
        
        //用流来计算
         list.stream()
                .filter(user -> {return user.getId()%2==0;})
                .filter(user -> {return user.getAge()>20;})
                .map(user -> {return user.getName().toUpperCase();})
                .limit(1)
                .forEach(System.out::println);


    }

运行结果:

B





问题5:假如最终结果是多个值,我想倒叙排列后只输出一个怎么办

    public void test2(){
        User user1 = new User(1,"a",23);
        User user2 = new User(2,"b",21);
        User user3 = new User(3,"c",29);
        User user4 = new User(4,"d",22);
        User user5 = new User(5,"e",18);

        List<User> list = Arrays.asList(user1,user2,user3,user4,user5);
        
        //用流来计算
         list.stream()
                .filter(user -> {return user.getId()%2==0;})
                .filter(user -> {return user.getAge()>20;})
                .map(user -> {return user.getName().toUpperCase();})
                .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
                .limit(1)
                .forEach(System.out::println);


    }

运行结果:

D





如果我们采用流计算来执行从0加到1_0000_0000的和,那这种方式所消耗的时间将只会是无脑for循环的十甚至几十分之一,效率极高。

   @Test
    public void test3(){
        long start = System.currentTimeMillis();
        Long sum = LongStream.rangeClosed(0L,1_0000_0000L).parallel().reduce(0,Long::sum);
        long end = System.currentTimeMillis();
        System.out.println("计算结果"+sum+"计算时间"+(end-start));
    }

运行结果:

计算结果5000000050000000计算时间177





对比,当然,如果计算量越大,流计算的优势就越明显。

@Test
public void test4(){
    long start = System.currentTimeMillis();
    Long sum = 0L;
    for (long i = 0L; i < 1_0000_0000L; i++) {
        sum+=i;
    }
    long end = System.currentTimeMillis();
    System.out.println("计算结果"+sum+"计算时间"+(end-start));
}

运行结果:

计算结果4999999950000000计算时间931

你可能感兴趣的:(java相关)