简体   繁体   中英

Question regarding functional interface in Java8

How does apply() method work in Java?

Regarding the UnaryOperator functional interface, I have read the documentation, it says

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

Represents an operation on a single operand that produces a result of the same type as its operand. This is a specialization of Function for the case where the operand and result are of the same type. This is a functional interface whose functional method is Function.apply(Object) .

What is the functional method?

I have the following class which implements UnaryOperator interface.

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

In the method call,

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

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

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

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

The map method implemented in Stream is responsible for calling the apply method of the Function that you've created.

Note : Uppercase implements UnaryOperator<T> extends Function<T, T> which is where the implementation of apply defined by you is called.

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

Indeed that is the role of Stream.map() implementation of calling apply() on it, therefore you will never do it when Stream.map() is invoked.

The abstract class ReferencePipeline does that:

@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 
                }
            };
        }
    };
}

map() defined in Stream is declared as :

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

Stream.map() expects a Function and by passing an UnaryOperator you provide all which is required.

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

Generally you don't implement directly the functional interface but you pass a lambda as that is more straight :

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

Yes it's exactly like toString() function invokes in println() function. println() accepts all the object, so by default toString() inherits from java.lang.Object class as well as Stream class's map() function accepts java.util.function.Function type objects which you exactly done implementing it with Uppercase class.

When it comes functional interfaces, functional interface is not just a interface which decorated with @FunctionalInterface annotation. Functional interface only could have one instance method. Could have many static and default methods though. These interfaces basically introduced to work with Java 8's new syntax type called Lambda Expressions . Otherwise this is just an interface.

Your solution implements like this if you want, creating a anonymous inner class;

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

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

No need to declare a separate concrete class like Uppercase . With the lambda expression, you can shorten the code like this;

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

This is the usage of functional interfaces' functional methods. This is only possible, when there is only one instance method . No need to implement separate class like you did.

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

This might be new to Java, but it's common in functional programming. The object can be treated as a function that has apply method to it. So when a new object is created, the apply method will be executed with the passed arguments.

The answer by Vlad Gudim has detailed expalined : https://stackoverflow.com/a/9738862/3812323

It's for the scala, but the holds true in functional paradigm.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM