Search code examples
javafunctionlambdainterfaceunary-operator

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.


Solution

  • 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())....