大家有没有发现java.util.function
包(本文后面简称function
包)下的接口虽然比较多(目前共43个),但都是定义很简单的(方法很少),而我们理解起来却十分的困难。其实啊,这也不怪大家,是因为这个包下的接口并不是典型的Java的API,你可以说它们是“异类”。那么问题来了,典型的Java API是什么样子的呢?function
包下的接口又“异”在哪里?
总所周知,Java是一种典型的OOP
(面向对象编程
)语言,封装、继承、多态自不必多说,大家想必都十分清楚了。但这里为了解释上面的问题,彬哥还是得多啰嗦几句。面向对象一个很重要的标识就是,把结构和行为封装到一个类(对象)中。
典型的Java API就是这样子的,举个大家都很熟悉的例子:java.util.List
。List是一个接口,是接口就只有方法,没有属性。但是,咱们来看看的List中的方法:size()、isEmpty()、contains(Object o)等等,按照正常人的思维,很容易、也很自然会将这些方法理解成:“假设我是个List的对象(实例)话,你们调用我的size()方法,我会将我的size告诉你;调用我的isEmpty()方法,我会告诉你我是不是空的;调用我的contains()方法,我会告诉你我是不是包含了你指定的这个对象”。大家有没有发现点什么?所有这些方法,很自然的加入到“我”这个语境(context)中去了。
那么再来看看这个咱们这个专题的主角function
包看,找个典型代表出来:java.util.function.Consumer<T>
。Consumer
是个Functional
接口,有且只有一个“抽象方法”--void accept(T t)
。这个accept方法谁能告诉我这™是什么鬼?彬哥现在也不知道,这还真不是彬哥故意卖关子。这是因为啊,你可以function
包下的接口都是“无意义的”,这个“无意义”并不是说它们没有存在的意义,而是说它们都必须放到具体的语境中去才会真正的意义。或者说,它们是“非典型”的Java API就体现在,它们自己是没有语境(Context)的,它们实际上可以说就是为Lambda表达式而存在的--你不需要了解他叫什么(匿名的),它们是作为参数在对象的方法的中传递的。
它们没有自己的结构,只定义行为,这很不OOP
,但很FP
(Functional Programming),所以你可以说,从JDK 8开始,函数也可以被称作Java世界中的“第一公民”了。
来看个具体的例子,java.lang.Iterable
的forEach
方法:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
它的参数就是个Consumer
,从forEach
这个方法的定义来看,现在我们可以理解到“遍历我所包含的所有元素,对每个元素都执行一次action.accept()”,还有点抽象?不过已经有些好理解了是吧?咱们再进一步看:
List<String> list = new ArrayList<>();
list.add("Hello ");
list.add("彬哥!");
list.forEach(s -> System.out.println(s)); // 这里当然也可以用更为简洁的方法引用来改写
现在在具体的语境里来理解就很容易了,“对于list中的每一个元素,执行我传进去的那个函数--Consumer”。可能咱们每天都在用类似的写法,但可能从来都没有意识到,那原来就是个Consumer
啊。这不怪大家,因为“它们都是无意义的”,就像在这里,你根本不需要知道我们其实最后是调用的了Consumer
的accept
方法。
其实啊,所有java.util.function包下的接口的方法名,我们都不必关心,因为当我们用它们的时候,压根不会去显式地调用它们,方法名也是“无意义”的,它们只是方便大家去理解他的用途。但是,方法的参数和返回值是需要我们关心和注意的。
function
包下总共有43个接口,嗯~看上去数量还是不少。不必害怕,其实满打满算也就这么5类:Function
、Supplier
、Consumer
、Predicate
、Operator
。这么看就很少了吧。这还不只,它们还有很多相似的地方,咱们再根据这些相似点分类、举一反三,就会简单很多。这里先按照这些共性的点,给这43个接口细分下归类:
-
Function类
-
一元:
Function
-
原始类型
- 作为参数:
DoubleFunction
,IntFunction
,LongFunction
- 作为返回值:
ToDoubleFunction
,ToIntFunction
,ToLongFunction
- 相互转化:
DoubleToIntFunction
,DoubleToLongFunction
,IntToDoubleFunction
,IntToLongFunction
,LongToDoubleFunction
,LongToIntFunction
- 作为参数:
-
-
二元:
BiFunction
-
原始类型
- 作为返回值:
ToDoubleBiFunction
,ToIntBiFunction
,ToLongBiFunction
- 作为返回值:
-
-
-
Supplier类
-
一元:
Supplier
-
原始类型
- 作为返回值:
BooleanSupplier
,DoubleSupplier
,IntSupplier
,LongSupplier
- 作为返回值:
-
-
-
Consumer类
-
一元:
Consumer
-
原始类型
- 作为参数:
DoubleConsumer
,IntConsumer
,LongConsumer
- 作为参数:
-
-
二元:
BiConsumer
-
原始类型
- 作为参数:
ObjDoubleConsumer
,ObjIntConsumer
,ObjLongConsumer
- 作为参数:
-
-
-
Predicate类
-
一元:
Predicate
-
原始类型
- 作为参数:
DoublePredicate
,IntPredicate
,LongPredicate
- 作为参数:
-
- 二元:
BiPredicate
-
-
Operator类
-
一元:
UnaryOperator
-
原始类型
- 同时作为参数和返回值:
DoubleUnaryOperator
,IntUnaryOperator
,LongUnaryOperator
- 同时作为参数和返回值:
-
-
二元:
BinaryOperator
-
原始类型
- 同时作为参数和返回值:
DoubleBinaryOperator
,IntBinaryOperator
,LongBinaryOperator
- 同时作为参数和返回值:
-
-
“额~彬哥,你这么把它们都列出来,搞得我更晕啦!”
别担心,对于它们每一类、每一个接口到底是什么?怎么用?咱们后面的章节都会一一具体说明。这个分类,一来,可以帮助大家先有个大体上的认识;二来,也可以作为后面章节的一个大纲,同时方便大家搞忘的时候来查阅。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。