1. Mike Strobel
  2. Procyon

Wiki

Clone wiki

Procyon / Decompiler Output Comparison

Lambdas and Method Handles ('::' operator)

Original Code

public void testLambdasAndMethodGroups() {
    final String[] words = {"one", "two", "three", "four", "five"};

    final StringBuilder result = Streams
            .intRange(0, 5)
            .collect(
                    StringBuilder::new,
                    (sb, i) -> sb.append(sb.length() > 0 ? ", " : "").append(words[i]),
                    (a, b) -> {}
            );

    System.out.println(result);
}

Decompiled Output

public void testLambdasAndMethodGroups() {
    final String[] words = new String[] { "one", "two", "three", "four", "five" };
    /// EDITED: Line breaks added for comprehension.
    final StringBuilder result = (StringBuilder)Streams.intRange(0, 5).collect(
        StringBuilder::new,
        (sb, n) -> sb.append((sb.length() > 0) ? ", " : "").append(words[n]),
        (sb, sb2) -> {}
    );
    System.out.println(result);
}

JD-GUI Output

---------------------------
Error
---------------------------
Invalid input file 'W:\J8Test\out\production\J8Test\LambdaTests.class'.

Annotation Declaration

Original Code

@interface NestedAnnotation {
    float value();
}

@interface TestAnnotation {
    String value() default "";
    String name() default "";
    char[] characters() default { };
    int integer() default 0;
    double real() default 0d;
    NestedAnnotation nested() default @NestedAnnotation(0f);
}

Decompiled Output

@interface NestedAnnotation {
    float value();
}

@interface TestAnnotation {
    String value() default "";

    String name() default "";

    char[] characters() default {};

    int integer() default 0;

    double real() default 0.0;

    NestedAnnotation nested() default @NestedAnnotation(0.0f);
}

JD-GUI Output

@interface NestedAnnotation
{
    public abstract float value();
}

@interface TestAnnotation
{
    public abstract String value();

    public abstract String name();

    public abstract char[] characters();

    public abstract int integer();

    public abstract double real();

    public abstract NestedAnnotation nested();
}

java.lang.String::lastIndexOf()

Original Code

static int lastIndexOf(
    final char[] source, final int sourceOffset, final int sourceCount,
    final char[] target, final int targetOffset, final int targetCount,
    int fromIndex) {
    /*
     * Check arguments; return immediately where possible. For
     * consistency, don't check for null str.
     */
    final int rightIndex = sourceCount - targetCount;
    if (fromIndex < 0) {
        return -1;
    }
    if (fromIndex > rightIndex) {
        fromIndex = rightIndex;
    }
    /* Empty string always matches. */
    if (targetCount == 0) {
        return fromIndex;
    }

    final int strLastIndex = targetOffset + targetCount - 1;
    final char strLastChar = target[strLastIndex];
    final int min = sourceOffset + targetCount - 1;
    int i = min + fromIndex;

startSearchForLastChar:
    while (true) {
        while (i >= min && source[i] != strLastChar) {
            i--;
        }
        if (i < min) {
            return -1;
        }
        int j = i - 1;
        final int start = j - (targetCount - 1);
        int k = strLastIndex - 1;

        while (j > start) {
            if (source[j--] != target[k--]) {
                i--;
                continue startSearchForLastChar;
            }
        }
        return start - sourceOffset + 1;
    }
}

Decompiler Output

static int lastIndexOf(final char[] source, final int sourceOffset, final int sourceCount, final char[] target, final int targetOffset, final int targetCount, int fromIndex) {
    final int rightIndex = sourceCount - targetCount;
    if (fromIndex < 0) {
        return -1;
    }
    if (fromIndex > rightIndex) {
        fromIndex = rightIndex;
    }
    if (targetCount == 0) {
        return fromIndex;
    }
    final int strLastIndex = targetOffset + targetCount - 1;
    final char strLastChar = target[strLastIndex];
    final int min = sourceOffset + targetCount - 1;
    int i = min + fromIndex;
Label_0062:
    while (true) {
        if (i >= min && source[i] != strLastChar) {
            --i;
        }
        else {
            if (i < min) {
                break;
            }
            int j = i - 1;
            final int start = j - (targetCount - 1);
            int k = strLastIndex - 1;
            while (j > start) {
                if (source[j--] != target[k--]) {
                    --i;
                    continue Label_0062;
                }
            }
            return start - sourceOffset + 1;
        }
    }
    return -1;
}

JD-GUI Output

static int lastIndexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)
{
    int rightIndex = sourceCount - targetCount;
    if (fromIndex < 0) {
        return -1;
    }
    if (fromIndex > rightIndex) {
        fromIndex = rightIndex;
    }

    if (targetCount == 0) {
        return fromIndex;
    }

    int strLastIndex = targetOffset + targetCount - 1;
    char strLastChar = target[strLastIndex];
    int min = sourceOffset + targetCount - 1;
    int i = min + fromIndex;
    int start;
    for (;;)
    {
        if ((i >= min) && (source[i] != strLastChar)) {
            i--;
        } else {
            if (i < min) {
                return -1;
            }
            int j = i - 1;
            start = j - (targetCount - 1);
            int k = strLastIndex - 1;
            do {
                if (j <= start) break;
            } while (source[(j--)] == target[(k--)]);
            i--;
        }
    }

    return start - sourceOffset + 1;
}

Generic compare() Method

Original Code

public static <T extends Comparable<? super T>> int compare(final T o1, final T o2) {
    if (o1 == null) {
        return o2 == null ? 0 : -1;
    }
    return o1.compareTo(o2);
}

Decompiler Output

public static <T extends Comparable<? super T>> int compare(T o1, T o2) {
    if (o1 == null) {
        return (o2 != null) ? -1 : 0;
    }
    return o1.compareTo(o2);
}

JD-GUI Output

public static <T extends Comparable<? super T>> int compare(T o1, T o2)
{
    if (o1 == null) {
        return o2 == null ? 0 : -1;
    }
    return o1.compareTo(o2);
}

Parameter Annotations

Original Code

public void testParameterAnnotations(
    @TestAnnotation final int i,
    @TestAnnotation(nested = @NestedAnnotation(123.45f)) final int j) {
}

Decompiler Output

public void testParameterAnnotations(
    @TestAnnotation int i,
    @TestAnnotation(nested = @NestedAnnotation(123.45f)) int j) {
}

JD-GUI Output

public void testParameterAnnotations(
    @TestAnnotation int i,
    @TestAnnotation(nested=@NestedAnnotation(123.45F)) int j) {}

Assert Statements

Original Code

public void testAssertStatements(final int i) {
    assert i != 0;
    assert i > 0 : "value must be a positive number";
}

Decompiler Output

public void testAssertStatements(int i) {
    assert i != 0;
    assert i > 0 : "value must be a positive number";
}

JD-GUI Output

public void testAssertStatements(int i)
{
    assert (i != 0);
    assert (i > 0) : "value must be a positive number";
}

Enum Switch Statements

Original Code

public enum Color { RED, BLUE }

public void testEnumSwitch(final Color color) {
    switch (color) {
        case BLUE:
            System.out.println("hi");
            break;
        case RED:
            System.out.println("go away");
            break;
    }
}

Decompiler Output

public enum Color
{
    RED,
    BLUE;
}

public void testEnumSwitch(Color color) {
    switch (color) {
        case BLUE:
            System.out.println("hi");
            break;
        case RED:
            System.out.println("go away");
            break;
    }
}

JD-GUI Output

public static enum Color {
    RED,  BLUE;
    private Color() {}
}
public void testEnumSwitch(Color color) { switch (2.$SwitchMap$com$strobel$decompiler$DecompilerTests$Color[color.ordinal()]) {
    case 1:
        System.out.println("hi");
        break;
    case 2:
        System.out.println("go away");
}
}

String Switch Statements

Original Code

public void testStringSwitch(final String s) {
    switch (s.toLowerCase()) {
        case "1":
        case "2":
        case "3":
            System.out.println(s);
            break;

        case "Aa":
        case "BB":
            System.out.println(s.toUpperCase());
            break;

        default:
            System.out.println(s);
            break;
    }
}

Decompiler Output

public void testStringSwitch(String s) {
    final String lowerCase = s.toLowerCase();
    switch (lowerCase) {
        case "1":
        case "2":
        case "3":
            System.out.println(s);
            break;
        case "Aa":
        case "BB":
            System.out.println(s.toUpperCase());
            break;
        default:
            System.out.println(s);
            break;
    }
}

JD-GUI Output

public void testStringSwitch(String s)
{
    String str = s.toLowerCase();int i = -1; switch (str.hashCode()) {case 49:  if (str.equals("1")) i = 0;  break; case 50:  if (str.equals("2")) i = 1;  break; case 51:  if (str.equals("3")) i = 2;  break; case 2112:  if (str.equals("BB")) i = 4; else if (str.equals("Aa")) i = 3;  break; }  switch (i) {
    case 0:
    case 1:
    case 2:
        System.out.println(s);
        break;

    case 3:
    case 4:
        System.out.println(s.toUpperCase());
        break;

    default:
        System.out.println(s);
}
}

Anonymous Local Types

Original Code

private boolean x;

public Iterable<String> testAnonymousLocalType(final boolean z) {
    return new Iterable<String>() {
        private final boolean y = z;

        @Override
        public Iterator<String> iterator() {
            return new Iterator<String>() {
                @Override
                public boolean hasNext() {
                    return x && y;
                }

                @Override
                public String next() {
                    return null;
                }

                @Override
                public void remove() {
                }
            };
        }
    };
}

Decompiler Output

private boolean x;

public Iterable<String> testAnonymousLocalType(boolean z) {
    return new Iterable<String>() {
        private final boolean y = z;

        public Iterator<String> iterator() {
            return new Iterator<String>() {
                public boolean hasNext() {
                    return DecompilerTests.this.x && Iterable.this.y;
                }

                public String next() {
                    return null;
                }

                public void remove() {
                }
            };
        }
    };
}

JD-GUI Output

private boolean x;

public Iterable<String> testAnonymousLocalType(final boolean z) {
    new Iterable() {
        private final boolean y = z;

        public Iterator<String> iterator()
        {
            new Iterator()
            {
                public boolean hasNext() {
                    return (DecompilerTests.this.x) && (DecompilerTests.1.this.y);
                }

                public String next()
                {
                    return null;
                }

                public void remove() {}
            };
        }
    };
}

Named Local Types

Original Code

public Iterable<String> testNamedLocalType(final boolean z) {
    final class MethodScopedClass implements Iterable<String> {
        private final boolean y = z;

        @Override
        public Iterator<String> iterator() {
            return new Iterator<String>() {
                @Override
                public boolean hasNext() {
                    return x && y;
                }

                @Override
                public String next() {
                    return null;
                }

                @Override
                public void remove() {
                }
            };
        }
    }
    ;

    System.out.println(new MethodScopedClass());

    return new MethodScopedClass();
}

Decompiler Output

public Iterable<String> testNamedLocalType(boolean z) {
    final class MethodScopedClass implements Iterable<String>
    {
        private final boolean y = z;

        MethodScopedClass() {
            super();
        }

        public Iterator<String> iterator() {
            return new Iterator<String>() {
                public boolean hasNext() {
                    return DecompilerTests.this.x && MethodScopedClass.this.y;
                }

                public String next() {
                    return null;
                }

                public void remove() {
                }
            };
        }
    }

    System.out.println(new MethodScopedClass());
    return new MethodScopedClass();
}

JD-GUI Output

public Iterable<String> testNamedLocalType(final boolean z)
{
    System.out.println(new Iterable() { private final boolean y = z;

        public Iterator<String> iterator()
        {
            new Iterator()
            {
                public boolean hasNext() {
                    return (DecompilerTests.1MethodScopedClass.this.this$0.x) && (DecompilerTests.1MethodScopedClass.this.y);
                }

                public String next()
                {
                    return null;
                }

                public void remove() {}
            };
        }
    });
    new Iterable() { private final boolean y = z;

        public Iterator<String> iterator()
        {
            new Iterator()
            {
                public boolean hasNext() {
                    return (DecompilerTests.1MethodScopedClass.this.this$0.x) && (DecompilerTests.1MethodScopedClass.this.y);
                }

                public String next()
                {
                    return null;
                }

                public void remove() {}
            };
        }
    };
}

Enhanced 'for' Loops

Original Code

public void testEnhancedForLoop(final String... items) {
    for (final String item : items) {
        System.out.println(item);
    }
}

Decompiler Output

public void testEnhancedForLoop(String[] items) {
    for (String item : items) {
        System.out.println(item);
    }
}

JD-GUI Output

public void testEnhancedForLoop(String[] items) {
    for (String item : items) {
        System.out.println(item);
    }
}

String Concatenation

Original Code

public String testStringConcatenation(final String s, final char c, final byte b, final float f, final Date d) {
    return b + ":" + c + ":" + s + ":" + f + ":" + d;
}

Decompiler Output

public String testStringConcatenation(String s, char c, byte b, float f, Date d) {
    return b + ":" + c + ":" + s + ":" + f + ":" + d;
}

JD-GUI Output

public String testStringConcatenation(String s, char c, byte b, float f, Date d) {
    return b + ":" + c + ":" + s + ":" + f + ":" + d;
}

Array Creation

Original Code

public int[] testArrayCreation(final boolean initialize) {
    if (initialize) {
        return new int[] { 1, 2, 3 };
    }
    return new int[3];
}

public int[][] testJaggedArrayInitialization() {
    return new int[][] { { 1, 2, 3 }, { 4, 5, 6 } };
}

public int[][] testMultiDimensionalArrayCreation() {
    return new int[3][2];
}

Decompiler Output

public int[] testArrayCreation(boolean initialize) {
    if (initialize) {
        return new int[] { 1, 2, 3 };
    }
    return new int[3];
}

public int[][] testJaggedArrayInitialization() {
    return new int[][] { { 1, 2, 3 }, { 4, 5, 6 } };
}

public int[][] testMultiDimensionalArrayCreation() {
    return new int[3][2];
}

JG-GUI Output

public int[] testArrayCreation(boolean initialize)
{
    if (initialize) {
        return new int[] { 1, 2, 3 };
    }
    return new int[3];
}

public int[][] testJaggedArrayInitialization() {
    return new int[][] { { 1, 2, 3 }, { 4, 5, 6 } };
}

public int[][] testMultiDimensionalArrayCreation() {
    return new int[3][2];
}

Complex Inner Class Relations

Original Code

public class InnerClassMadness {
    public static void main(final String[] args) {
        final InnerClassMadness t = new InnerClassMadness();
        final A a = t.new A();
        final A.B b = a.new B(a);
        final A.D d = a.new D(a, b);
        final A.D d2 = new Object() {
            class Inner {
                A.D getD() {
                    final InnerClassMadness t = new InnerClassMadness();
                    final A a = t.new A();
                    final A.B b = a.new B(a);
                    final A.D d = a.new D(a, b);
                    return d;
                }
            }
        }.new Inner().getD();
    }

    public class A extends InnerClassMadness {
        public A() {
        }

        public class B extends A {
            public B(final A a) {
                a.super();
            }

            public class C extends B {
                public C(final A a) {
                    a.super(a);
                }
            }
        }

        public class D extends B.C {
            public D(final A a, final B b) {
                b.super(a);
            }
        }
    }
}

Decompiler Output

public class InnerClassMadness
{
    public static void main(final String[] args) {
        final InnerClassMadness t = new InnerClassMadness();
        final A a = t.new A();
        final A.B b = a.new B(a);
        final A.D d = a.new D(a, b);
        final A.D d2 = new Object() {
            class Inner
            {
                A.D getD() {
                    final InnerClassMadness t = new InnerClassMadness();
                    final A a = t.new A();
                    final A.B b = a.new B(a);
                    final A.D d = a.new D(a, b);
                    return d;
                }
            }
        }.new Inner().getD();
    }

    public class A extends InnerClassMadness
    {
        public class D extends B.C
        {
            public D(final A a, final B b) {
                b.super(a);
            }
        }

        public class B extends A
        {
            public B(final A a) {
                a.super();
            }

            public class C extends B
            {
                public C(final A a) {
                    a.super(a);
                }
            }
        }
    }
}

JD-GUI Output

public class InnerClassMadness
{
  public static void main(String[] args)
  {
    InnerClassMadness t = new InnerClassMadness();
    InnerClassMadness tmp13_12 = t; tmp13_12.getClass(); A a = new A();
    A tmp27_26 = a; tmp27_26.getClass(); InnerClassMadness.A.B b = new InnerClassMadness.A.B(tmp27_26, a);
    A tmp42_41 = a; tmp42_41.getClass(); InnerClassMadness.A.D d = new InnerClassMadness.A.D(tmp42_41, a, b);
    void tmp65_62 = new Object() {
      class Inner {
        Inner() {  } 
        InnerClassMadness.A.D getD() { InnerClassMadness t = new InnerClassMadness();
          InnerClassMadness tmp13_12 = t; tmp13_12.getClass(); InnerClassMadness.A a = new InnerClassMadness.A(tmp13_12);
          InnerClassMadness.A tmp27_26 = a; tmp27_26.getClass(); InnerClassMadness.A.B b = new InnerClassMadness.A.B(tmp27_26, a);
          InnerClassMadness.A tmp42_41 = a; tmp42_41.getClass(); InnerClassMadness.A.D d = new InnerClassMadness.A.D(tmp42_41, a, b);
          return d;
        }
      }
    };
    tmp65_62.getClass(); InnerClassMadness.A.D d2 = new InnerClassMadness.1.Inner(tmp65_62).getD();
  }

  public class A extends InnerClassMadness
  {
    public A()
    {
    }

    public class D extends InnerClassMadness.A.B.C
    {
      public D(InnerClassMadness.A a, InnerClassMadness.A.B b)
      {
        super(a);
      }
    }

    public class B extends InnerClassMadness.A
    {
      public B(InnerClassMadness.A a)
      {
        super();
      }

      public class C extends InnerClassMadness.A.B {
        public C(InnerClassMadness.A a) {
          super(a);
        }
      }
    }
  }
}

Enum with Abstract Method

Original Code

enum A {
    X {
        public void f() {
            System.out.println(this.name().toLowerCase());
        }
    },
    Y {
        public void f() {
            System.out.println("y");
        }
    };

    public abstract void f();
}

Decompiled Output

enum A
{
    X {
        public void f() {
            System.out.println(this.name().toLowerCase());
        }
    },
    Y {
        public void f() {
            System.out.println("y");
        }
    };

    public abstract void f();
}

JD-GUI Output

abstract enum A
{
  X,

  Y;

  public abstract void f();
}

Updated