Function::当需要 BiFunction<T, U, R> 时应用

Osi*_*ris 3 java lambda method-reference

我对以下行感到困惑:

Seq<String> s1 = seq.zip(split, Function::apply);
Run Code Online (Sandbox Code Playgroud)

在这个片段中:

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();
                    }
                });
            };
        }

    }

Run Code Online (Sandbox Code Playgroud)

我确实明白这Function::apply是一个方法引用,并且该方法需要一个BiFunction<T, U, R>. 但我不明白这是如何兼容的。

它到底解决了什么?Function::apply为什么在这种情况下我可以供货?

Zab*_*uza 5

非静态方法参考

这确实是一个有趣的规则,因为它使用了方法引用允许的特殊规则之一。

简单的例子,假设您需要一个Function<String, Integer>,那么可以写String::length,即使这个方法有不同的签名。请求的签名是:

Integer apply(String x) { ... }
Run Code Online (Sandbox Code Playgroud)

但我们提供了一个只有 的方法int length(),所以String根本没有参数。但是,该方法是非静态的,并且在 的实例上运行String。因此,Java 可以假设您打算在该实例上调用该方法,并由此推导出该方法的第一个参数。IE s -> s.length()


一般细节

您的设置中也会发生同样的情况。首先,您必须了解您请求的泛型BiFunction<T, U, R>解析的内容。他们是:

  • TUnaryOperator<String>
  • UString
  • RConsumer<T>, 所以Consumer<UnaryOperator<String>>

相当复杂,但是还可以。

实际签名

现在,请求的签名是:

Consumer<UnaryOperator<String>> apply(UnaryOperator<String> t, String u)
Run Code Online (Sandbox Code Playgroud)

当您提供方法引用时Function::apply,其签名为:

R apply(T t)
Run Code Online (Sandbox Code Playgroud)

所以,在这种情况下:

Consumer<UnaryOperator<String>> apply(String u)
Run Code Online (Sandbox Code Playgroud)

然后,再次从所需签名 ( UnaryOperator<String> t) 中的第一个参数中扣除,该方法Function::apply是对实例进行操作的非静态方法Function,该方法恰好与 兼容UnaryOperator<String>,因为UnaryOperator extends Function

执行

所以Function::apply本质上与实现您的 as 相同BiFunction

Consumer<UnaryOperator<String>> apply(UnaryOperator<String> t, String u) {
  return t.apply(u);
}
Run Code Online (Sandbox Code Playgroud)

从第一个参数获取函数并将其应用于第二个参数,返回结果。