关于 Java 的闭包
之前未能理解 Java 对闭包的说明中“effective final”的意思,现在对其进行了一番针对性学习。
这个词(实际上的 final)应当这样理解——在闭包中不能改变外界变量的“值”,这个“值”对基本类型来说是值,对引用类型来说是引用。这个问题的影响其实并不大——如果需要对变量的值进行改变,将其传入一个数组即可。
1 |
|
为什么不能改变外界变量的值?这里可以这样解释(事实上也大概就是如此)——Java 的闭包并非真正捕获外界变量(这种捕获是捕获了 C++风格的真正的引用,js,scheme 等语言的闭包都是如此,对这些语言来说,它们所定义的函数看待上层作用域中的变量,就像 if,for 块看待外层块作用域的时候一样),而是把对象的值复制(对基本类型是值,对对象来说是指针)并保存为自身的一个属性,所以如果原值改变,捕获值和原值就不同了,这就和闭包性质所要求的不一致了(这时候的性质类似函数调用,作为函数参数传入),因此禁止了被捕获对象的重新赋值。
Java 中的 lambda 表达式是残废的——要使用它必须先定义相应函数式接口,而不能像 kotlin,ts 等语言有所谓函数类型,可以直接应用,且对其的应用(apply)必须要通过其方法,这是比较麻烦的。
但是这些限制实际上影响不大——需要自定义接口的情况是较少的,Java 本身提供了比较丰富的接口定义可以直接使用,但是代价是增加理解成本;客户代码一般不会预先定义相关类型的变量并自己使用,而是直接通过 lambda 表达式构造相应实例并直接传递给相关方法中,将其的调用交由相关方法进行实现。
而 Java 的 lambda 的最大缺陷在于——其只能抛出在签名中指明能够抛出的异常!也就是说,如果用户自定义的 lambda 表达式可能出现异常,他必须进行 try-catch!这是极为不便的,目前的解决方案唯有定义自己的函数式接口用于抛出异常!这可不是我们想要的答案——对集合类型的 map-filter-reduce 操作中如果有异常,就必须要 try-catch,无法改变!这是无法理喻的,特别是当我们在 Spring 环境下工作,依赖全局异常处理来进行异常的时候,或者说将异常当作一种别样的控制流来处理的时候。
Java8 提供的java.util.function
包包含了许多可以直接应用的函数式接口,可以应付绝大部分简单业务情况——(下表引用于网络)
1 | BiConsumer<T,U> 代表了一个接受两个输入参数的操作,并且不返回任何结果 |
---|---|
2 | BiFunction<T,U,R> 代表了一个接受两个输入参数的方法,并且返回一个结果 |
3 | BinaryOperator |
4 | BiPredicate<T,U> 代表了一个两个参数的 boolean 值方法 |
5 | BooleanSupplier 代表了 boolean 值结果的提供方 |
6 | Consumer |
7 | DoubleBinaryOperator 代表了作用于两个 double 值操作符的操作,并且返回了一个 double 值的结果。 |
8 | DoubleConsumer 代表一个接受 double 值参数的操作,并且不返回结果。 |
9 | DoubleFunction |
10 | DoublePredicate 代表一个拥有 double 值参数的 boolean 值方法 |
11 | DoubleSupplier 代表一个 double 值结构的提供方 |
12 | DoubleToIntFunction 接受一个 double 类型输入,返回一个 int 类型结果。 |
13 | DoubleToLongFunction 接受一个 double 类型输入,返回一个 long 类型结果 |
14 | DoubleUnaryOperator 接受一个参数同为类型 double, 返回值类型也为 double 。 |
15 | Function<T,R> 接受一个输入参数,返回一个结果。 |
16 | IntBinaryOperator 接受两个参数同为类型 int, 返回值类型也为 int 。 |
17 | IntConsumer 接受一个 int 类型的输入参数,无返回值 。 |
18 | IntFunction |
19 | IntPredicate :接受一个 int 输入参数,返回一个布尔值的结果。 |
20 | IntSupplier 无参数,返回一个 int 类型结果。 |
21 | IntToDoubleFunction 接受一个 int 类型输入,返回一个 double 类型结果 。 |
22 | IntToLongFunction 接受一个 int 类型输入,返回一个 long 类型结果。 |
23 | IntUnaryOperator 接受一个参数同为类型 int, 返回值类型也为 int 。 |
24 | LongBinaryOperator 接受两个参数同为类型 long, 返回值类型也为 long。 |
25 | LongConsumer 接受一个 long 类型的输入参数,无返回值。 |
26 | LongFunction |
27 | LongPredicate R 接受一个 long 输入参数,返回一个布尔值类型结果。 |
28 | LongSupplier 无参数,返回一个结果 long 类型的值。 |
29 | LongToDoubleFunction 接受一个 long 类型输入,返回一个 double 类型结果。 |
30 | LongToIntFunction 接受一个 long 类型输入,返回一个 int 类型结果。 |
31 | LongUnaryOperator 接受一个参数同为类型 long, 返回值类型也为 long。 |
32 | ObjDoubleConsumer |
33 | ObjIntConsumer |
34 | ObjLongConsumer |
35 | Predicate |
36 | Supplier |
37 | ToDoubleBiFunction<T,U> 接受两个输入参数,返回一个 double 类型结果 |
38 | ToDoubleFunction |
39 | ToIntBiFunction<T,U> 接受两个输入参数,返回一个 int 类型结果。 |
40 | ToIntFunction |
41 | ToLongBiFunction<T,U> 接受两个输入参数,返回一个 long 类型结果。 |
42 | ToLongFunction |
43 | UnaryOperator |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 协议 ,转载请注明出处!