Может ли кто-нибудь распаковать эту очень краткую функцию Java в более подробный пример?

Я пытаюсь перенести это руководство по Java в Xojo. Я изо всех сил пытаюсь распаковать приведенную ниже функцию Set, потому что, хотя она короткая и элегантная, она вмещает множество преобразований в небольшое пространство, и я не уверен, правильно ли я ее понимаю. Это сложно, поскольку Java не является моим основным языком, а Xojo не поддерживает дженерики:

public interface GraphNode {
    String getId();
}


public class Graph<T extends GraphNode> {
    private final Set<T> nodes;
    private final Map<String, Set<String>> connections;

    public T getNode(String id) {
        return nodes.stream()
            .filter(node -> node.getId().equals(id))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("No node found with ID"));
    }

    public Set<T> getConnections(T node) {
        return connections.get(node.getId()).stream()
            .map(this::getNode)
            .collect(Collectors.toSet());
    }
}

Я в основном могу только понять, что происходит до вызова метода .stream():

  1. Получите Id из пройденных node GraphNode
  2. Получите Set<String> из connections Map, ключ которого соответствует полученному Id

Что я не понимаю, так это то, что здесь происходит:

.map(this::getNode).collect(Collectors.toSet())

Может ли кто-нибудь предоставить псевдокод, чтобы объяснить это?


person Garry Pettet    schedule 14.03.2020    source источник
comment
Отвечает ли это на ваш вопрос? Оператор :: (двойное двоеточие) в Java 8   -  person jonrsharpe    schedule 14.03.2020
comment
Поскольку у Xojo нет класса Set, вы можете просто использовать Dictionary с фиктивным значением (например, установить значение nil или true) вместо этого и сохранить элементы в качестве ключей Dictionary. Для getNode переберите все ключи и проверьте, соответствует ли какой-либо из них идентификатору, и если он соответствует, верните это первое совпадение. Для getConnections просмотрите словарь соединений, получите каждый их узел и поместите их в новый набор (например, словарь или массив).   -  person Thomas Tempelmann    schedule 14.03.2020


Ответы (2)


Потоки в основном прославлены циклами for-each. Как правило, когда вы видите XXX.stream() или метод, который возвращает Stream<XXX>, это означает "для каждой вещи в XXX" и "для каждого XXX..." соответственно.

Итак, здесь написано "для каждой строки в Set<String>..."

map означает "превратить каждую вещь во что-то другое", другими словами, преобразование. С циклом for в псевдокоде это выглядит так:

For Each x In set
    f(x)
Next x

f — это функция, которую вы передаете. В данном случае это getNode.

Теперь getNode возвращает T, поэтому каждый элемент в нашем исходном наборе был преобразован в T. Последний вызов — это collect, что означает поместить все эти элементы обратно в некоторую коллекцию или какой-либо другой объект. В этом случае мы помещаем все эти преобразованные Ts обратно в новый Set.

Весь код в псевдокоде будет таким:

originalSet = connections.get(node.getId())
newSet = []
For Each x In originalSet
    newSet.add(x)
Next x
person Sweeper    schedule 14.03.2020

это означает map id в Node и положить (собрать) его в set

this::getNode переводится как: из этого класса используйте getNode для id, который является просто синтаксическим сахаром для .map(id -> getNode(id)).collect(Collectors.toSet())

public T getNode(String id) {
        return nodes.stream()
            .filter(node -> node.getId().equals(id))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("No node found with ID"));
    }

Этот код возвращает первый узел с id в наборе узлов, nodes.stream() .filter(node -> node.getId().equals(id)) вернет набор, в котором каждому узлу передается id в качестве аргумента, findFirst() вернет первый узел в наборе.

public Set<T> getConnections(T node) {
        return connections.get(node.getId()).stream()
            .map(this::getNode)
            .collect(Collectors.toSet());
    }

поскольку connections является картой, connections.get(node.getId()) вернет значение с ключом node.getId(), затем map(this::getNode) сопоставит его с id в Node, используя getNode(String id), и, наконец, поместит его в set

person Fibi    schedule 14.03.2020