Препратка към верижен метод на 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