java-stream-函数式接口
一、概述
java是面向对象的,对象往往映射现实生活中的某个具体的东西,绝大多数保存在java内存的堆中;
java的函数式编程,则可以将对象指向一个函数(行为),而非具体的东西;
函数式接口可以表现为lambda表达式,把lambda表达式认为是一种匿名内部类有助于理解(注,以下都是这么认为的,但不是一回事),但两者之间有区别,区别我也不是很清楚;
函数式接口和普通接口的区别是函数式接口只能有一个抽象方法,可使用@FunctionalInterface注解进行约束和提醒;
jdk提供了很多可以直接使用的函数式接口,比较常用的有以下4种:
java.util.function |
|
Predicate |
断言型:有参数,输出固定为boolean |
Function |
公式型:有入参,有输出 |
Supplier |
产出型:没有入参,有输出 |
Consumer |
消费型:有入参,没有输出 |
二、stream中的函数式接口
1,Supplier(产出型:没有入参,有输出)
所以,Supplier是一个产出型的函数型接口,不需要入参,产出一个出参,此处即是new SelfLsit<>();
2,BiConsumer(消费型:有入参,没有输出;特点是有两个入参)
通过1中可知,collector参数如下:
上面的lambda表达式可以改写成匿名内部类:
new BiConsumer<SelfList<T>, T>() { @Override public void accept(SelfList<T> list, T t) { list.add(t); } }
所以,BiConsumer是一个类似于Consumer消费型的函数式接口,有入参没有产出;相比于Consumer,有两个入参;
本例中的两个入参分别是,1中产出的new SelfList<>()以及一个元素,所做的操作是向new SelfList<>()中添加这个元素;
3,Predicate(断言型:有参数,输出固定为boolean类型)
上面的lambda表达式可以改写成匿名内部类:
SelfList<Integer> greenAppleWightList = appleList.selfStream() //.filter(item -> "绿色".equals(item.getColor())) .filter(new Predicate<Apple>() { @Override public boolean test(Apple item) { return "绿色".equals(item.getColor()); } }) .map(Apple::getWeight) .collect(SelfCollectors.toList());
所以,Predicate是一个断言型的函数式接口;如本例中,有一个入参,期望入参的颜色是绿色的,符合预期则返回true,否则返回false;
4,Function(公式型:有入参,有出参)
上面的lambda表达式可以改写成匿名内部类:
SelfList<Integer> greenAppleWightList = appleList.selfStream() .filter(item -> "绿色".equals(item.getColor())) //.map(Apple::getWeight) .map(new Function<Apple, Integer>() { @Override public Integer apply(Apple item) { return item.getWeight(); } }) .collect(SelfCollectors.toList());
所以,Function是一个公式型的函数式接口,有一个入参和一个出参;
本例中,入参为苹果对象,出参为该苹果对象的重量;
5,Consumer(消费型:有入参,没有输出)
可以看出,函数式接口除了可以直接使用,还能够通过被继承的方式使用;
但是此处没有直接使用SelfSink(Consumer),而是用一个抽象类实现(implements)了这个函数式接口,然后用这个抽象类的匿名内部类多次重写这个函数式接口的抽象方法;
总结下来,归根结底,就是匿名内部类可以用同一套模板,多次重写某个(些)方法,生成多个匿名内部类,而不需要多个单独的java文件来定义;
不管是函数式接口的匿名内部类,还是抽象类的匿名内部类,还是实现了函数式接口的抽象类的匿名内部类;
好像没有什么(类、抽象类、接口)是不产生匿名内部类的,当然final的类是无法被继承的除外,可能还有一些其他情况;
所以,Consumer是一个消费型的函数式接口,只有入参没有出参;像kafka的consumer一样,消费消息,没有反馈,也有一些特殊场景需要反馈消息,如防止消息丢失;
三、总结
stream看似是个框架,使用了少量的类;
其实通过程序员传入的不同的入参,生成了很多匿名内部类:
函数式接口,不是完全的匿名内部类,函数式接口(使用lambda表达式)会在运行时(第一次使用时)生成字节码?匿名内部类编译后就是class。