我对下面的行感到困惑:
Seq<String> s1 = seq.zip(split, Function::apply);
在这个片段中:
static String underscoreToCamel(String str) {
UnaryOperator<String> capitalize = s -> s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
Seq<UnaryOperator<String>> seq = c -> {
c.accept(String::toLowerCase);
while (true) {
c.accept(capitalize);
}
};
List<String> split = Arrays.asList(str.split("_"));
Seq<String> s1 = seq.zip(split, Function::apply);
String a = s1.join("");
return a;
}
public interface Seq<T> {
void consume(Consumer<T> consumer);
static <T> Seq<T> unit(T t) {
return consumer -> consumer.accept(t);
}
default <E> Seq<E> map(Function<T, E> function) {
return consumer -> consume(t -> consumer.accept(function.apply(t)));
}
default <E> Seq<E> flatMap(Function<T, Seq<E>> function) {
return consumer -> consume(t -> function.apply(t).consume(consumer));
}
default String join(String sep) {
StringJoiner joiner = new StringJoiner(sep);
consume(t -> joiner.add(t.toString()));
return joiner.toString();
}
static <T> T stop() {
throw StopException.INSTANCE;
}
default void consumeTillStop(Consumer<T> consumer) {
try {
consume(consumer);
} catch (StopException ignore) {}
}
default <U, R> Seq<R> zip(Iterable<U> iterable, BiFunction<T, U, R> function) {
return c -> {
Iterator<U> iterator = iterable.iterator();
consumeTillStop(t -> {
if (iterator.hasNext()) {
c.accept(function.apply(t, iterator.next()));
} else {
stop();
}
});
};
}
}
我确实理解Function::apply
是一个方法引用,并且该方法需要一个BiFunction<T, U, R>
。但我不明白这是如何兼容的。
它到底要解决什么?为什么在这种情况下可以提供Function::apply
?
2条答案
按热度按时间9udxz4iz1#
非静态方法引用
这确实是一个有趣的例子,因为它使用了方法引用允许的“特殊规则”之一。
举个简单的例子,假设你需要一个
Function<String, Integer>
,那么你可以写String::length
,即使这个方法有不同的签名。请求的签名是:但是我们提供了一个只有
int length()
的方法,所以根本没有String
参数。但是,该方法是非静态的,并且在String
的示例上操作。因此Java可以假设您打算在该示例上调用该方法,并由此推导出该方法的第一个参数。即s -> s.length()
。通用详细信息
同样的情况也发生在你的设置中。首先,您必须了解所请求的
BiFunction<T, U, R>
的泛型解析为什么。它们是:T
:UnaryOperator<String>
U
:String
R
:Consumer<T>
,因此Consumer<UnaryOperator<String>>
很复杂,但还好。
实际签名
现在,请求的签名是:
当你给予你的方法引用
Function::apply
,其签名是:所以,在这种情况下:
然后,来自所需签名(
UnaryOperator<String> t
)的第一个参数再次从Function::apply
是一个在Function
示例上操作的非静态方法这一事实中扣除,因为UnaryOperator extends Function
恰好与UnaryOperator<String>
兼容。实现
因此,
Function::apply
本质上与实现BiFunction
是相同的:从第一个参数中获取函数并将其应用于第二个参数,返回结果。
yacmzcpb2#
Function::apply
是一个方法引用,引用Seq s1 = seq.zip(split, Function::apply)
行中Function接口的apply方法。它用作zip方法的第二个参数,该方法需要一个BiFunction
函数接口,并预期一个接受两个T
和U
类型参数并返回R
类型结果的函数接口。在这个例子中,
T
是一个UnaryOperator<String>
(来自Seq<UnaryOperator<String>> seq)
),U
是一个String(来自List<String> split
),当执行zip方法时,R
是一个String。由于String::apply
与Function接口的apply方法具有相同的签名,后者接受String类型的单个参数并返回String,因此它被用作Function::apply
方法的引用。seq函数序列将通过zip方法应用于拆分列表的每个元素,并迭代拆分列表的元素。Function接口的apply方法将用于将seq中的每个
UnaryOperator<String>
应用于split中相应的String元素。