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>
.
One of the major reason for introducing default methods in interfaces is to enhance the Collections API in Java 8 to support lambda expressions. If any class in the hierarchy has a method with same signature, then default methods become irrelevant. A default method cannot override a method from java.
Java 8 introduces default method so that List/Collection interface can have a default implementation of forEach method, and the class implementing these interfaces need not implement the same.
A functional interface can contain default and static methods which do have an implementation, in addition to the single unimplemented method.
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
.
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);
The andThen
method of Function
is used as a pipe between functions.
Both your Function
s 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.
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
.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With