关于 Java8 中功能接口的问题

Question regarding functional interface in Java8

apply() 方法在 Java 中如何工作?

关于UnaryOperator函数式接口,我看了文档,上面写着

@FunctionalInterface
public interface UnaryOperator<T> extends Function<T,T>

表示对单个操作数的操作,产生与其操作数类型相同的结果。这是 Function 的特化,适用于操作数和结果属于同一类型的情况。 这是一个函数式接口,它的函数式方法是Function.apply(Object).

函数方法是什么?

我有以下 class 实现了 UnaryOperator 接口。

    public class Uppercase implements UnaryOperator<String> {
        @Override
        public String apply(String s) {
            return s.trim().toUpperCase();
        }
    }

在方法调用中,

    new Stream().map(new Uppercase())

它将任何输入流转换为大写。我的问题是,是否会自动调用 Uppercase class 中的 apply() 方法? (是不是像toString()方法被println()方法自动调用了?)

如果不显式调用 apply() 方法,我找不到任何示例。所以请帮助我了解这里发生了什么。

does the apply() method in Uppercase class get called automatically?

Stream中实现的map方法负责调用您创建的Functionapply方法。

注意: Uppercase implements UnaryOperator<T> extends Function<T, T> 也就是你定义的apply的实现被调用的地方.

It converts whatever input stream into uppercase. My question is, does the apply() method in Uppercase class get called automatically?

确实是Stream.map()实现调用apply()的作用,所以当Stream.map()被调用时你永远不会这样做。

摘要 class ReferencePipeline 这样做:

@SuppressWarnings("unchecked")
public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
    Objects.requireNonNull(mapper);
    return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
        @Override
        Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
            return new Sink.ChainedReference<P_OUT, R>(sink) {
                @Override
                public void accept(P_OUT u) {
                    downstream.accept(mapper.apply(u)); // <------ HERE 
                }
            };
        }
    };
}
Stream 中定义的

map() 声明为:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

Stream.map() 期望 Function 并通过传递 UnaryOperator 您提供所有必需的。

I couldn't find any example without calling apply() method explicitly. So please help me understand what happened here.

通常您不直接实现功能接口,而是传递一个 lambda,因为这样更直接:

new Stream().map(s->s.trim().toUpperCase())....

是的,它与 toString() 函数在 println() 函数中调用完全一样。 println() 接受所有对象,因此默认情况下 toString() 继承自 java.lang.Object class 以及 Stream class 的 map()函数接受 java.util.function.Function 类型的对象,您使用 Uppercase class 完全实现了它。

说到函数式接口,函数式接口不仅仅是一个用@FunctionalInterface注解装饰的接口。功能接口只能有一个实例方法。虽然可以有许多 staticdefault 方法。这些接口基本上是为了与 Java 8 的新语法类型 Lambda Expressions 一起工作而引入的。否则这只是一个接口。

如果你愿意,你的解决方案可以这样实现,创建一个匿名内部 class;

new Stream().map(new Function() {

    @Override
    public String apply(String s) {
        return s.trim().toUpperCase();
    }
});

无需像 Uppercase 那样声明单独的具体 class。使用 lambda 表达式,您可以像这样缩短代码;

new Stream().map(s -> s.trim().toUpperCase());

这是函数式接口的函数式方法的用法。这只有在只有一个 实例方法 时才有可能。无需像您那样实施单独的 class。

In computer science, Apply is a function that applies functions to arguments.

这对 Java 来说可能是新的,但它在函数式编程中很常见。 该对象可以被视为具有 apply 方法的函数。所以当一个新的对象被创建时,apply 方法将被传递的参数执行。

Vlad Gudim 的回答有详细的解释:

它适用于 scala,但在函数范式中也适用。