SGr
SGr

Reputation: 853

Java 8 Lambda overloading

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

Answers (6)

Yogu
Yogu

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

w25r
w25r

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

TechTrip
TechTrip

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

Volune
Volune

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

soulcheck
soulcheck

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

Marko Topolnik
Marko Topolnik

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

Related Questions