How to overload a Function with generic parameter in Java 8?
public class Test {
List list = new ArrayList<>();
public int sum(Function function) {
return list.stream().map(function).reduce(Integer::sum).get();
}
public double sum(Function function) {
return list.stream().map(function).reduce(Double::sum).get();
}
}
Error: java: name clash:
sum(java.util.function.Function) and
sum(java.util.function.Function) have the same erasure
解决方案
The example you present in your question has got nothing to do with Java 8 and everything to do with how generics work in Java. Function function and Function function will go through type-erasure when compiled and will be transformed to Function. The rule of thumb for method overloading is to have different number, type or sequence of parameters. Since both your methods will transform to take a Function argument, the compiler complains about it.
That being said, srborlongan has already provided one way to resolve the issue. The problem with that solution is that you have to keep modifying your Test class for each and every type of operation (addition,subtraction,etc) on different types (Integer,Double, etc). An alternate solution would be to use method overriding instead of method overloading :
Change the Test class a bit as follows :
public abstract class Test {
List list = new ArrayList<>();
public O performOperation(Function function) {
return list.stream().map(function).reduce((a,b)->operation(a,b)).get();
}
public void add(I i) {
list.add(i);
}
public abstract O operation(O a,O b);
}
Create a subclass of Test that will add two Integers.
public class MapStringToIntAddtionOperation extends Test {
@Override
public Integer operation(Integer a,Integer b) {
return a+b;
}
}
Client code can then use the above code as follows :
public static void main(String []args) {
Test test = new MapStringToIntAddtionOperation();
test.add("1");
test.add("2");
System.out.println(test.performOperation(Integer::parseInt));
}
The advantage of using this approach is that your Test class is in line with the open-closed principle. To add a new operation such as multiplication, all you have to do is add a new subclass of Test and override the operation method to multiply two numbers. Club this with the Decorator pattern and you can even minimize the number of sub-classes that you have to create.
Note The example in this answer is indicative. There are a lot of areas of improvement (such as make Test a functional interface instead of an abstract class) which are beyond the scope of the question.