Използвайте препратка към метод с параметър

Току-що започнах да изучавам Java потоци и се сблъсках с проблем. Моля, разгледайте следния пример. Това е част от клас Node:

private Map<String, Node> nodes;

public Optional<Node> child(String name) {
    return Optional.<Node>ofNullable(nodes.get(name));
}

private void findChildren(String name, List<Node> result) {
    child(name).ifPresent(result::add);
    nodes.values().stream()
//          .map(Node::findChildren(name, result))
//          .forEach(Node::findChildren(name, result))
            .forEach(node -> node.findChildren(name, result));
}

Намерението ми беше да извикам #findChildren с име и параметри за резултат на всеки възел в потока. Опитах се да използвам препратките към метода Node::findChildren без успех. Бих оценил решения, различни от това с оператор ->.

Възможно ли е по някакъв начин да се използва препратката към метода заедно с параметър? Харесва ми идеята за потоци и просто искам да направя кода по-четлив.

Всъщност мисля, че има подобен въпрос Препратки към метод с параметър, който прочетох, но не мога да разбера как да използвам метода bind2 в моя код. Единственото решение ли е?


person matepal297    schedule 23.04.2015    source източник
comment
Можете да предавате препратки към метод само когато се изискват функционални интерфейси с подобен подпис (т.е. възможно е да се изведат аргументи към ламбда)   -  person Alex Salauyou    schedule 24.04.2015
comment
forEach() очаква единичен аргумент Node и връща void, така че там може да бъде предадена само препратка към статичен метод, приемащ единичен Node, или метод без аргумент на клас Node с връщане void. Решение: създайте такъв метод сами.   -  person Alex Salauyou    schedule 24.04.2015
comment
marcin-chwedczuk.github.io/method-references-in-java- 8 са някои добри примери за хора, които търсят препратки към методи с аргументи.   -  person anuj pradhan    schedule 02.04.2018


Отговори (1)


Не можете да използвате препратки към методи за тази цел. Трябва да прибягвате до ламбда изрази. Причината, поради която методът bind2 на свързания въпрос не работи, е, че всъщност се опитвате да свържете два параметъра, за да конвертирате функция с три аргумента във функция с един аргумент. Няма подобно просто решение, тъй като няма стандартен функционален interface за потребители с три аргумента.

Би трябвало да изглежда така

interface ThreeConsumer<T, U, V> {
    void accept(T t, U u, V v);
}
public static <T, U, V> Consumer<T> bind2and3(
                        ThreeConsumer<? super T, U, V> c, U arg2, V arg3) {
    return (arg1) -> c.accept(arg1, arg2, arg3);
}

Тогава .forEach(bind2and3(Node::findChildren, name, result)); може да работи. Но това наистина ли е по-просто от .forEach(node -> node.findChildren(name, result));?

person Holger    schedule 24.04.2015
comment
Благодаря ти! Как е конверторът Node::findChildren с 2 параметъра в ThreeConsumer, който приема 3 параметъра? - person matepal297; 24.04.2015
comment
За методи, които не са static, трябва да броите приемника на метода като параметър. Във вашия конкретен случай потребителят се извиква с Node екземпляр като параметър, на който ще бъде извикан методът findChildren. Е, това важи, ако използвате ClassName::methodName за препратка към метод на екземпляр. Вместо това можете да обвържете препратка към метод към определен приемник, като кажете object::methodName, тогава методът ще бъде извикан на object. Това се случва напр. когато кажете System.out::println, където методът println ще бъде извикан на екземпляра PrintStream, намерен в System.out. - person Holger; 24.04.2015
comment
Но във вашия случай искате да обработите поток от различни Node екземпляри, така че да оставите приемника необвързан и да го броите като параметър е това, което искате. Вижте също тук - person Holger; 24.04.2015
comment
Още един час за разтапяне на мозъка, само за да разберете, че не можете. - person Mihai Morcov; 07.02.2017