java 函数::当需要BiFunction〈T,U,R>时应用

ehxuflar  于 2023-04-28  发布在  Java
关注(0)|答案(2)|浏览(147)

我对下面的行感到困惑:

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

9udxz4iz

9udxz4iz1#

非静态方法引用

这确实是一个有趣的例子,因为它使用了方法引用允许的“特殊规则”之一。
举个简单的例子,假设你需要一个Function<String, Integer>,那么你可以写String::length,即使这个方法有不同的签名。请求的签名是:

Integer apply(String x) { ... }

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

通用详细信息

同样的情况也发生在你的设置中。首先,您必须了解所请求的BiFunction<T, U, R>的泛型解析为什么。它们是:

  • TUnaryOperator<String>
  • UString
  • RConsumer<T>,因此Consumer<UnaryOperator<String>>

很复杂,但还好。

实际签名

现在,请求的签名是:

Consumer<UnaryOperator<String>> apply(UnaryOperator<String> t, String u)

当你给予你的方法引用Function::apply,其签名是:

R apply(T t)

所以,在这种情况下:

Consumer<UnaryOperator<String>> apply(String u)

然后,来自所需签名(UnaryOperator<String> t)的第一个参数再次从Function::apply是一个在Function示例上操作的非静态方法这一事实中扣除,因为UnaryOperator extends Function恰好与UnaryOperator<String>兼容。

实现

因此,Function::apply本质上与实现BiFunction是相同的:

Consumer<UnaryOperator<String>> apply(UnaryOperator<String> t, String u) {
  return t.apply(u);
}

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

yacmzcpb

yacmzcpb2#

Function::apply是一个方法引用,引用Seq s1 = seq.zip(split, Function::apply)行中Function接口的apply方法。它用作zip方法的第二个参数,该方法需要一个BiFunction函数接口,并预期一个接受两个TU类型参数并返回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元素。

相关问题