1

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"?

1
  • Rather than use Function<T, T> you can shorthand to UnaryOperator<T> Commented Sep 18, 2014 at 22:05

6 Answers 6

9

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.

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

2 Comments

So no matter what, there's no way to do test.apply(5) and test.apply("5") and get the behavior I described in the question?
You can, but definitely not using a lambda to implement test::apply. A pedestrian implementation of a custom interface would be the only way.
6

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.

Comments

4

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);
}

2 Comments

This is an elegant solution, very cool. Especially like the use of method references.
To pull the values off the stream you could do .findFirst().get(), such as Stream.of(5).map(test::apply).findFirst().get()
2

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.

Comments

1

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.

Comments

0

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.

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.