前言
方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。
当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些。方法引用是一种更简洁易懂的Lambda表达式。
注意:方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。
在Java8中,使用方法引用非常简单,如String::isEmpty
,但无法使用它否定的方法引用。本文内容即如何解决此问题使得我们能够更加全面地使用方法引用。
首先看一个使用方法引用的例子:
1
|
Stream.of( "A" , "" , "B" ).filter(String::isEmpty).count() |
上面代码的输出为1,即空字符串的数目。如果我们想要获取非空字符串的数目,就不能直接使用方法引用了。
1
|
Stream.of( "A" , "" , "B" ).filter(s -> !s.isEmpty()).count() |
Java8中的Predicate,有predicate.negate()可以转换为断言的否定形式,但String::isEmpty
却无法这么做(String::isEmpty.negate()
或者!String::isEmpty
)。因为方法引用并不是一个lambda或者函数接口,它能够被解析为一个或者多个函数接口。如,String::isEmpty
至少可以被解析如下:
1
2
|
Predicate<String> Function<String, Boolean> |
为了解决上述的问题,我们可以通过某种机制显式地将方法引用转换为一个函数接口:
1
2
3
|
public static <T> Predicate<T> as(Predicate<T> predicate) { return predicate; } |
通过使用一个静态方法,接受方法引用参数,返回一个函数接口,即可实现方法引用到函数接口的转换。接着,我们就可以使用方法引用来实现上面例子中的获取非空字符串的数目。
1
|
Stream.of( "A" , "" , "B" ).filter(as(String::isEmpty).negate()).count(); |
进一步还能使用各种组合的Predicate。
1
|
.filter(as(String::isEmpty).negate().and( "A" ::equals)) |
由于一个方法引用可能会被解析为多种函数接口,因此如果我们实现很多参数不同的as方法,那么很容易造成混淆。更好的方式则是在方法名中加入函数参数的类型来区分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
import java.util.function.*; public class FunctionCastUtil { public static <T, U> BiConsumer<T, U> asBiConsumer(BiConsumer<T, U> biConsumer) { return biConsumer; } public static <T, U, R> BiFunction<T, U, R> asBiFunction(BiFunction<T, U, R> biFunction) { return biFunction; } public static <T> BinaryOperator<T> asBinaryOperator(BinaryOperator<T> binaryOperator) { return binaryOperator; } public static <T, U> BiPredicate<T, U> asBiPredicate(BiPredicate<T, U> biPredicate) { return biPredicate; } public static BooleanSupplier asBooleanSupplier(BooleanSupplier booleanSupplier) { return booleanSupplier; } public static <T> Consumer<T> asConsumer(Consumer<T> consumer) { return consumer; } public static DoubleBinaryOperator asDoubleBinaryOperator(DoubleBinaryOperator doubleBinaryOperator) { return doubleBinaryOperator; } public static DoubleConsumer asDoubleConsumer(DoubleConsumer doubleConsumer) { return doubleConsumer; } public static <R> DoubleFunction<R> asDoubleFunction(DoubleFunction<R> doubleFunction) { return doubleFunction; } public static DoublePredicate asDoublePredicate(DoublePredicate doublePredicate) { return doublePredicate; } public static DoubleToIntFunction asDoubleToIntFunction(DoubleToIntFunction doubleToIntFunctiontem) { return doubleToIntFunctiontem; } public static DoubleToLongFunction asDoubleToLongFunction(DoubleToLongFunction doubleToLongFunction) { return doubleToLongFunction; } public static DoubleUnaryOperator asDoubleUnaryOperator(DoubleUnaryOperator doubleUnaryOperator) { return doubleUnaryOperator; } public static <T, R> Function<T, R> asFunction(Function<T, R> function) { return function; } public static IntBinaryOperator asIntBinaryOperator(IntBinaryOperator intBinaryOperator) { return intBinaryOperator; } public static IntConsumer asIntConsumer(IntConsumer intConsumer) { return intConsumer; } public static <R> IntFunction<R> asIntFunction(IntFunction<R> intFunction) { return intFunction; } public static IntPredicate asIntPredicate(IntPredicate intPredicate) { return intPredicate; } public static IntSupplier asIntSupplier(IntSupplier intSupplier) { return intSupplier; } public static IntToDoubleFunction asIntToDoubleFunction(IntToDoubleFunction intToDoubleFunction) { return intToDoubleFunction; } public static IntToLongFunction asIntToLongFunction(IntToLongFunction intToLongFunction) { return intToLongFunction; } public static IntUnaryOperator asIntUnaryOperator(IntUnaryOperator intUnaryOperator) { return intUnaryOperator; } public static LongBinaryOperator asLongBinaryOperator(LongBinaryOperator longBinaryOperator) { return longBinaryOperator; } public static LongConsumer asLongConsumer(LongConsumer longConsumer) { return longConsumer; } public static <R> LongFunction<R> asLongFunction(LongFunction<R> longFunction) { return longFunction; } public static LongPredicate asLongPredicate(LongPredicate longPredicate) { return longPredicate; } public static <T> LongSupplier asLongSupplier(LongSupplier longSupplier) { return longSupplier; } public static LongToDoubleFunction asLongToDoubleFunction(LongToDoubleFunction longToDoubleFunction) { return longToDoubleFunction; } public static LongToIntFunction asLongToIntFunction(LongToIntFunction longToIntFunction) { return longToIntFunction; } public static LongUnaryOperator asLongUnaryOperator(LongUnaryOperator longUnaryOperator) { return longUnaryOperator; } public static <T> ObjDoubleConsumer<T> asObjDoubleConsumer(ObjDoubleConsumer<T> objDoubleConsumer) { return objDoubleConsumer; } public static <T> ObjIntConsumer<T> asObjIntConsumer(ObjIntConsumer<T> objIntConsumer) { return objIntConsumer; } public static <T> ObjLongConsumer<T> asObjLongConsumer(ObjLongConsumer<T> objLongConsumer) { return objLongConsumer; } public static <T> Predicate<T> asPredicate(Predicate<T> predicate) { return predicate; } public static <T> Supplier<T> asSupplier(Supplier<T> supplier) { return supplier; } public static <T, U> ToDoubleBiFunction<T, U> asToDoubleBiFunction(ToDoubleBiFunction<T, U> toDoubleBiFunction) { return toDoubleBiFunction; } public static <T> ToDoubleFunction<T> asToDoubleFunction(ToDoubleFunction<T> toDoubleFunction) { return toDoubleFunction; } public static <T, U> ToIntBiFunction<T, U> asToIntBiFunction(ToIntBiFunction<T, U> toIntBiFunction) { return toIntBiFunction; } public static <T> ToIntFunction<T> asToIntFunction(ToIntFunction<T> ioIntFunction) { return ioIntFunction; } public static <T, U> ToLongBiFunction<T, U> asToLongBiFunction(ToLongBiFunction<T, U> toLongBiFunction) { return toLongBiFunction; } public static <T> ToLongFunction<T> asToLongFunction(ToLongFunction<T> toLongFunction) { return toLongFunction; } public static <T> UnaryOperator<T> asUnaryOperator(UnaryOperator<T> unaryOperator) { return unaryOperator; } private FunctionCastUtil() { } } Stream.of( "A" , "" , "B" ).filter(asPredicate(String::isEmpty).negate()).count(); |
英文原文:https://dzone.com/articles/put-your-java-8-method-references-to-work
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:http://www.rowkey.me/blog/2017/09/02/java8-method-reference-work/