5

I am learning Java-8 Lambda, I am trying to understand addThen default method in java.util.function.Function interface.As per my understanding addthen will first execute the First function and then it will execute the second method. So I created a program like below:

//Pojo class 
  class Bike {

    public Bike(String bikeName, int price, String bikeType) {
        this.bikeName = bikeName;
        this.price = price;
        this.bikeType = bikeType;
    }

    private String bikeType;
    private String bikeName;
    private int price;

    public String getBikeType() {
        return bikeType;
    }

    @Override
    public String toString() {
        return "Bike [bikeType=" + bikeType + ", bikeName=" + bikeName + ", price=" + price + "]";
    }

    public void setBikeType(String bikeType) {
        this.bikeType = bikeType;
    }

    public String getBikeName() {
        return bikeName;
    }

    public void setBikeName(String bikeName) {
        this.bikeName = bikeName;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

}

//Main class
public class FunctionInbuildDefaultMethodsExample {

    public static void main(String[] args) {
        learningAndThen();
    }

    static void learningAndThen() {

        Function<Bike, String> updateBikefunction = (Bike bike) -> {
            System.out.println("OldBike Name is::" + bike.getBikeName());
            bike.setBikeName("PULSOR-200CC");
            return bike.getBikeName();
        };

        Function<Bike, String> updateBikePriceFunction = (Bike bike) ->  {

            System.out.println("OldBike Price is::" + bike.getPrice());
            bike.setPrice(95000);
            return bike.getBikeName();

        };

        /*
         * First update Bike and then price
         * */
         /*Compilation error here*/
        Function<Bike,String> bikeFunction = updateBikefunction.andThen(updateBikePriceFunction);
        bikeFunction.apply( new Bike("PULSOR-125CC", 65000, "BAJAJ"));

    }
 }

I am getting an compilation error at the line

 Function<Bike,String> bikeFunction =
updateBikefunction.andThen(updateBikePriceFunction);

as

"The method andThen(Function) in the type Function is not applicable for the arguments (Function)"

, After looking into the source code of Function interface , I understand that addThen default method is looking for instance of type Function<String,Book>. My questions is, If addThen default method is supposed to execute the first function and then the next fuction which is passed as parameter , why the addThen default method of function interface is written in such a manner excepting instance of type Function<String,Book>.

4 Answers 4

4

andThen is applied to the result of that Function. So this would work for example:

Function<Bike, String> bikeFunction = updateBikefunction
                                       .andThen(s -> s.toUpperCase());

Since the result is a String from that Function.

Sign up to request clarification or add additional context in comments.

Comments

3
updateBikefunction = Bike -> String
updateBikePriceFunction = Bike -> String

updateBikefunction -> updateBikePriceFunction = Bike -> String -> Bike -> String
                                                        ^^^^^^^^^^^^^^

To form a chain of functions, the previous result should be an output for the next function. Here is this condition is broken.

The updateBikefunction could be changed to a Function<Bike, Bike>

    Function<Bike, Bike> updateBikefunction = (Bike bike) -> {
        ...
        return bike;
    };

to compile the line:

Function<Bike, String> bikeFunction = updateBikefunction.andThen(updateBikePriceFunction);

Comments

3

The andThen method of Function is used as a pipe between functions.

Both your Functions are take in a Bike and return a String, that's the problem.

When you invoke [function1].andThen[function2] where both have the same parametrization of <Bike, String>, [function2] is expecting a Bike, but receiving a String from [function1].

See docs (my bold):

Returns a composed function that first applies this function to its input, and then applies the after function to the result. If evaluation of either function throws an exception, it is relayed to the caller of the composed function.

Comments

2

Explanation

It's rather simple. A function does not output tuples like (Bike, String), it has an input Bike and an output String.

If you now compose functions, then the second function needs to use that output as its input like:

Function1: A -> B
Function2: B -> C
Composed:  A (-> B) -> C

Your functions are both

updateBikefunction:      Bike -> String
updateBikePriceFunction: Bike -> String

however the compiler expects the updateBikePriceFunction to use the output of updateBikefunction as its input, so it wants it to look like:

updateBikePriceFunction: String -> ...

You can also clearly see this in the documentation:

Interface Function<T,R>

andThen(Function<? super R,? extends V> after)

So the object on which you invoke the method has input T and output R. The function you need to use as argument has input ? super R and output ? extends V.


How to Fix

If you want to chain manipulation methods you should use Bike -> Bike and create an own method for such final results like getBikeNameFunction which then returns the name:

Function<Bike, Bike> updateBikefunction = (Bike bike) -> {
    System.out.println("OldBike Name is::" + bike.getBikeName());
    bike.setBikeName("PULSOR-200CC");
    return bike;
};

Function<Bike, Bike> updateBikePriceFunction = (Bike bike) ->  {
    System.out.println("OldBike Price is::" + bike.getPrice());
    bike.setPrice(95000);
    return bike;
};

Function<Bike, String> getBikeNameFunction = (Bike bike) -> {
    return bike.getBikeName();
};

You can now use it this way:

Function<Bike, String> bikeFunction = updateBikefunction
    .andThen(updateBikePriceFunction)
    .andThen(getBikeNameFunction);

Or alternatively just use the reference to the method like:

Function<Bike, String> bikeFunction = updateBikefunction
    .andThen(updateBikePriceFunction)
    .andThen(Bike::getName);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.