Ссылка на связанный метод Java 8?

Предположим, есть типичный Java Bean:

class MyBean {
    void setA(String id) {
    }

    void setB(String id) { 
    }

    List<String> getList() {
    }
}

И я хотел бы создать более абстрактный способ вызова сеттеров с помощью BiConsumer:

Map<SomeEnum, BiConsumer<MyBean, String>> map = ...
map.put(SomeEnum.A, MyBean::setA);
map.put(SomeEnum.B, MyBean::setB);
map.put(SomeEnum.List, (myBean, id) -> myBean.getList().add(id));

Есть ли способ заменить лямбду (myBean, id) -> myBean.getList().add(id) ссылкой на связанный метод, что-то вроде (myBean.getList())::add или myBean::getList::add или что-то еще?


person Random42    schedule 19.03.2015    source источник
comment
Что делает map.put(SomeEnum.List, (myBean, id) -> myBean.getList().add(id));?   -  person Andremoniy    schedule 19.03.2015
comment
Нет, нет. Ссылки на методы не поддерживают цепочку. В вашем примере было бы неясно, какой из двух методов должен получить второй параметр. В любом случае, зачем тебе это?   -  person Holger    schedule 19.03.2015
comment
@Andremoniy Вставляет карту, BiConsumer в виде лямбда.   -  person Random42    schedule 19.03.2015
comment
@Holger Я бы хотел сделать это по той же причине, по которой я бы написал ссылку на метод вместо лямбда. При вызове String str = obj.getList().get(0); будет ли str ссылаться на то, что возвращает getList() или что get(0)? Я считаю, что семантика может быть такой же для возможной ссылки на цепной метод.   -  person Random42    schedule 19.03.2015
comment
@ m3th0dman: вы говорите о возвращаемом значении. Я спросил о параметре. В вашем примере вы предполагаете, что второй параметр BiConsumer переходит ко второму методу, но нет причин, по которым компилятор должен предполагать то же самое.   -  person Holger    schedule 19.03.2015
comment
@Holger Ну, я считаю, что компилятор, реализующий это, должен быть последовательным с вызовом метода. В любом случае ассоциативность оператора :: не будет проблемой, если такая функция будет реализована.   -  person Random42    schedule 19.03.2015
comment
Вы называете это «последовательным», потому что это ваше ожидание. Но нет правила, объясняющего, почему ваша гипотетическая ссылка на два метода должна вести себя как (x,y)->x.foo().bar(y), а не как (x,y)->x.foo(y).bar(). Ссылки на методы также могут относиться к static методам, поэтому они также могут быть (x,y)->Type.foo(x).bar(y) или (x,y)->Type.foo(x, y).bar() или (x,y)-> Type.foo().bar(x,y) или (x,y)->Type2.bar(Type1.foo(x), y) или (x,y)-> Type2.bar(Type1.foo(x, y)) или (x,y)->Type2.bar(Type1.foo(), x, y) или (x,y)-> Type2.bar(x.foo(), y) или (x,y)->Type2.bar(x.foo(y))   -  person Holger    schedule 19.03.2015


Ответы (1)


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


Но если вы настаиваете на этом…

static <V,T,U> BiConsumer<V,U> filterFirstArg(BiConsumer<T,U> c, Function<V,T> f) {
    return (t,u)->c.accept(f.apply(t), u);
}

BiConsumer<MyBean, String> c = filterFirstArg(List::add, MyBean::getList);

Название метода предполагает, что он принимает существующий BiConsumer (здесь List.add) и добавляет функцию (здесь MyBean.getList()) к ее первому аргументу. Несложно представить, как может выглядеть эквивалентный служебный метод для фильтрации второго аргумента или обоих сразу.

Однако в основном это полезно для объединения существующих реализаций с другой операцией. В вашем конкретном примере сайт использования не лучше обычного лямбда-выражения

BiConsumer<MyBean, String> c = (myBean, id) -> myBean.getList().add(id);
person Holger    schedule 19.03.2015
comment
Принятие на основе первого комментария — ссылки на методы не поддерживают цепочку. - person Random42; 16.04.2015