Reputation: 853
I can't seem to be able to make it work.
Function<Integer, Integer> test = x -> x+x;
Function<String, String> test = x -> x+x;
yields
Duplicate local variable
test
How can I make it so that test.apply(5)
returns 10 and test.apply("5")
returns "55"?
Upvotes: 1
Views: 1083
Reputation: 9445
You can't, and the problem is type erasure.
You would need a single object that is both a Function<Integer, Integer>
and a Function<String, String>
, so that it has two apply
methods:
class MyFunc implements Function<Integer, Integer>, Function<String, String> {
public Integer apply(Integer v) { return x + x; }
public String apply(String v) { return x + x; }
}
However, the Java compiler could not possibly compile this because bytecode does not have the concept of generics, so the two interfaces would be the same and indistinguishable.
Upvotes: 1
Reputation: 882
In honor of Test Driven Development, I'll just throw in my whole JUnit test:
@Test
public void shouldWork() {
UnaryOperator<Object> test = x -> {
if (x instanceof Integer) {
int intValue = (Integer) x;
return intValue + intValue;
}
return x.toString() + x.toString();
};
Assert.assertEquals(10, test.apply(5));
Assert.assertEquals("55", test.apply("5"));
}
This is question is kind of a collision of Object Oriented programming and Functional programming.
Upvotes: 2
Reputation: 4537
Despite the problems with your code above trying to "overload a variable" this can be done. A quick but ugly solution is as follows:
@SuppressWarnings("unchecked")
public static <T> T addOrConcat(T x){
if (x instanceof String){
String ret = x.toString();
return (T)(ret + ret);
} else if (x instanceof Integer){
Integer ret = (Integer)x + (Integer)x;
return (T)(ret);
}
return null;
}
public static void main(String[] args) {
UnaryOperator<Object> test = x -> addOrConcat(x);
System.out.println(test.apply(Integer.valueOf(5)));
System.out.println(test.apply("5"));
}
The output would be as follows:
10
55
Given time I think one could come up with something more efficient, safer and intuitive.
Upvotes: 0
Reputation: 4339
You can't have a test
variable of an anonymous function that implement both Function<Integer, Integer>
and Function<String, String>
(which is by the way the same interface).
You can however have a nested class with an overloaded apply
method, and eventually construct it with lambda functions. This nested class doesn't need to (and can't) implements both Function<Integer, Integer>
and Function<String, String>
. But as shown in the following example, you actually don't need to implements these interfaces:
static class FunctionOverload {
private final Function<String, String> stringFunction;
private final Function<Integer, Integer> integerFunction;
FunctionOverload(Function<String, String> stringFunction, Function<Integer, Integer> integerFunction) {
this.stringFunction = stringFunction;
this.integerFunction = integerFunction;
}
public String apply(String string) {
return this.stringFunction.apply(string);
}
public Integer apply(Integer integer) {
return this.integerFunction.apply(integer);
}
}
public static void main(String[] args) {
FunctionOverload test = new FunctionOverload(x -> x + x, x -> x + x);
test.apply("5");
test.apply(5);
Stream.of("5").map(test::apply);
Stream.of(5).map(test::apply);
}
Upvotes: 4
Reputation: 36767
To put it simply: you can't.
What you're doing isn't overloading. It's creating two separate instances of a Function
interface with clashing names.
It's equivalent to doing:
int a = 1;
int a = 2;
in the same scope, and equally illegal.
Overloading would take place if you could have two apply
definitions in Function
interface - one taking String
argument and one taking int
. You can't (easily) modify existing interfaces in java.
Upvotes: 6
Reputation: 200138
test
is a variable, it is not a method. You cannot overload a variable.
You might try to make an interface with two method signatures, but the result wouldn't be a functional interface and you couldn't implement it with a lambda. So again, we fail.
Upvotes: 9