2014-09-18 3 views
1

Я не могу заставить работать.Java 8 Перегрузка Lambda

Function<Integer, Integer> test = x -> x+x; 
Function<String, String> test = x -> x+x; 

дает

Duplicate локальную переменную test

Как я могу сделать это так, что test.apply(5) возвращает 10 и test.apply("5")возвращается "55"?

+0

Вместо того чтобы использовать функции вы можете обсчитывать к UnaryOperator TechTrip

ответ

9

test - это переменная, это не метод. Вы не можете перегружать переменную.

Возможно, вы попытаетесь создать интерфейс с двумя сигнатурами методов, но результат не будет функциональным интерфейсом, и вы не сможете реализовать его с помощью лямбда. Так что снова мы терпим неудачу.

+0

Поэтому независимо от того, что нет никакого способа, чтобы сделать 'test.apply (5)' и 'test.apply («5»)' и получить поведение я описал в вопросе? – SGr

+0

Вы можете, но определенно не использовать лямбда для реализации 'test :: apply'. Единственным способом было бы реализовать пешеходную реализацию пользовательского интерфейса. –

6

Проще говоря: вы не можете.

Что вы делаете, это не перегрузка. Он создает два отдельных экземпляра интерфейса Function с именами конфликтов.

Это эквивалентно делать:

int a = 1; 
int a = 2; 

в том же объеме и в равной степени незаконным.

Перегрузки будет иметь место, если вы могли бы иметь два apply определения в Function интерфейса - один принимая String аргумент и один принимая int. Вы не можете (легко) изменить существующие интерфейсы в java.

4

Вы не можете использовать переменную test анонимной функции, которая реализует как Function<Integer, Integer>, так и Function<String, String> (что, кстати, тот же интерфейс).

Однако вы можете иметь вложенный класс с перегруженным методом apply и в конечном итоге построить его с помощью лямбда-функций. Этот вложенный класс не должен (и не может) реализовывать как Function<Integer, Integer>, так и Function<String, String>. Но, как показано в следующем примере, вы на самом деле не нужен реализуют эти интерфейсы:

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

Это элегантное решение, очень круто. Особенно нравится использование ссылок на методы. – TechTrip

+1

Чтобы вывести значения из потока, который вы могли бы сделать .findFirst(). Get(), например Stream.of (5) .map (test :: apply) .findFirst(). Get() – TechTrip

0

Несмотря на проблемы с вашим кодом выше, пытаясь «перегрузить переменный» это может быть сделано. Быстрый, но некрасиво решение выглядит следующим образом:

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

Выход будет выглядеть следующим образом:

Учитывая раз, когда я думаю, что можно было бы придумать что-то более эффективное, более безопасным и интуитивным.

2

В честь Test Driven Development, я просто бросить в целом мой тест JUnit:

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

Это вопрос вид столкновения объектно-ориентированного программирования и функционального программирования.

1

Вы не можете, и проблема заключается в стирании типа.

Вы должны были бы один объект, который является одновременно Function<Integer, Integer> и Function<String, String>, так что у него есть два apply методы:

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

Однако компилятор Java не может, возможно, скомпилировать это потому, что байткод не имеют концепция дженериков, поэтому оба интерфейса будут одинаковыми и неразличимыми.

Смежные вопросы