I used CFR and output looks good. It understands generics, formatting is clean. Not sure if naming (local variable ) can be better. Here is an example which shows the naming problem.
See output from java.util.ArrayDequeue(
private void doubleCapacity() {
int n;
assert (this.head == this.tail);
int n2 = this.head;
int n3 = this.elements.length;
int n4 = n3 - n2;
if ((n = n3 << 1) < 0) {
throw new IllegalStateException("Sorry, deque too big");
}
Object[] arrobject = new Object[n];
System.arraycopy(this.elements, n2, arrobject, 0, n4);
System.arraycopy(this.elements, 0, arrobject, n4, n2);
this.elements = arrobject;
this.head = 0;
this.tail = n3;
}
Compare that against original
private void doubleCapacity() {
assert head == tail;
int p = head;
int n = elements.length;
int r = n - p; // number of elements to the right of p
int newCapacity = n << 1;
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
Object[] a = new Object[newCapacity];
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);
elements = (E[])a;
head = 0;
tail = n;
}
Getting a context based name will be out of scope for most decompilers.
The author has link to his friends project, procyon, opensource. It has own comparison page. From the page...
The Procyon decompiler handles language enhancements from Java 5 and
beyond that most other decompilers don't. It also excels in areas
where others fall short. Procyon in particular does well with:
Enum declarations
Enum and String switch statements (only tested against javac 1.7 so far)
Local classes (both anonymous and named)
Annotations
Java 8 Lambdas and method references (i.e., the :: operator).