public boolean hasCycle() {
    Set<Node> looped = findCycles();
    if (looped.isEmpty()) {
      return false;
    }

    Set<Node> checkingSet = new HashSet<>(looped);

    checkingSet.retainAll(startingNodes);
    if (!checkingSet.isEmpty()) {
      // a starting node is part of the loop
      return true;
    }

    Deque<Node> processingQueue = new ArrayDeque<>();
    for (Node n : startingNodes) {
      processingQueue.push(n);
      do {
        Node current = processingQueue.pop();
        if (looped.contains(current)) {
          // there is a path leading from a starting node to the detected loop
          return true;
        }
        for (Edge e : current.outgoing) {
          processingQueue.push(e.to);
        }
      } while (!processingQueue.isEmpty());
    }
    return false;
  }
@Test
  void hasCycle() {
    CallGraph callGraph = new CallGraph();
    callGraph.addEdge("a", "b");
    callGraph.addEdge("a", "c");
    callGraph.addEdge("b", "d");
    callGraph.addEdge("c", "d");
    callGraph.addEdge("c", "b");
    callGraph.addEdge("d", "b");
    callGraph.addStarting(new CallGraph.Node("a"));

    assertTrue(callGraph.hasCycle());
  }