views:

599

answers:

2

I want to use a PriorityQueue to do a topological sort on a graph. For brevity, I'd like to use an anonymous inner class for the comparator. However, I need access to the graph g in order to determine the in degree of the nodes I'm looking at. Is this possible?

 /**
 * topological sort 
 * @param g must be a dag
 */
public static Queue<String> topoSort(DirectedGraph<String, DefaultEdge> g) {
 Queue<String> result = new PriorityQueue<String>(g.vertexSet().size(), 
   new Comparator<String>() {

    DirectedGraph<String, DefaultEdge> g;

    @Override
    public int compare(String arg0, String arg1) {
     if (g.inDegreeOf(arg0) < g.inDegreeOf(arg1)) {
      return -1;
     }
     if (g.inDegreeOf(arg0) > g.inDegreeOf(arg1)) {
      return 1;
     }
     return 0;
    }
 });

 result.addAll(g.vertexSet());

 return result;
}

CORRECTED CODE

/**
 * topological sort 
 * @param g must be a dag
 */
public static Queue<String> topoSort(final DirectedGraph<String, DefaultEdge> g) {
 Queue<String> result = new PriorityQueue<String>(g.vertexSet().size(), 
   new Comparator<String>() {   
    @Override
    public int compare(String arg0, String arg1) {
     if (g.inDegreeOf(arg0) < g.inDegreeOf(arg1)) {
      return -1;
     }
     if (g.inDegreeOf(arg0) > g.inDegreeOf(arg1)) {
      return 1;
     }
     return 0;
    }
 });

 result.addAll(g.vertexSet());

 return result;
}
+4  A: 

Yes, make it final:

public static Queue<String> topoSort(final DirectedGraph<String, DefaultEdge> g) {

See The Final Word On the final Keyword:

Anonymous Local Classes

The second situation involving final variables is actually mandated by language semantics. In that situation, the Java compiler won't let you use a variable unless it is declared final. This situation arises with closures, also known as anonymous local classes. Local classes can only reference local variables and parameters that are declared final.

public void doSomething(int i, int j)
{
  final int n = i + j; // must be declared final

  Comparator comp = new Comparator()
  {
    public int compare(Object left, Object right)
    {
      return n; // return copy of a local variable
    }
  };
}

The reason for this restriction becomes apparent if we shed some light on how local classes are implemented. An anonymous local class can use local variables because the compiler automatically gives the class a private instance field to hold a copy of each local variable the class uses. The compiler also adds hidden parameters to each constructor to initialize these automatically created private fields. Thus, a local class does not actually access local variables, but merely its own private copies of them. The only way this can work correctly is if the local variables are declared final, so that they are guaranteed not to change. With this guarantee in place, the local class is assured that its internal copies of the variables accurately reflect the actual local variables.

cletus
what does that do for anything?
Rosarch
If you don't make if final the compiler won't let you reference it.
bmargulies
ah yes, that is correct.
Rosarch
g has to be final, not the DefaultEdge...
TofuBeer
A: 

FYI, with google collections you also have the option of

  Ordering.natural().onResultOf(
      new Function<String, Integer>() {
        public Integer apply(String arg) {
          return g.inDegreeOf(arg);
        }
      });

This doesn't necessarily save you a lot of typing, as you can see, unless you can find other uses for that Function, but it does shield you from the bugs that very often creep into your by-hand comparator implementations.

Kevin Bourrillion