I'm trying to port this Java tutorial to Xojo. I'm struggling to unpack the Set
function below because, whilst short and elegant, it crams a lot of conversions into a small space and I'm not sure if I'm understanding it correctly. It's difficult as Java is not my primary language and Xojo lacks support for generics:
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());
}
}
I basically can only figure what is happening up to the .stream()
method call:
Id
of the passed node
GraphNode
Set<String>
from the connections
Map
whose key matches the retrieved Id
What I don't understand is what is happening here:
.map(this::getNode).collect(Collectors.toSet())
Can someone provide pseudocode to explain this?
Streams are basically glorified for-each loops. Generally, when you see XXX.stream()
or a method that returns a Stream<XXX>
, it means "for each thing in XXX
" and "For each XXX..." respectively.
So, here it says "for each string in the Set<String>
..."
map
means "turn each thing into something else", in other words, a transformation. With a for loop, it's like this in pseudocode:
For Each x In set
f(x)
Next x
f
is the function that you pass in. In this case, it's getNode
.
Now, getNode
returns T
, so every element in our original set has been transformed into a T
. The last call is a collect
, which means to put all these elements back into some collection, or some other object. In this case, we put all these transformed T
s back into a new Set
.
The whole code in pseudocode would be:
originalSet = connections.get(node.getId())
newSet = []
For Each x In originalSet
newSet.add(x)
Next x