Did you know about Local Classes in Java?

Did you know that you could declare classes inside code blocks i.e. methods, constructors, static blocks, etc?  Such classes are called Local Classes.  For example, the following would compile and run:

public class SayHello {

    public void sayHello(final String name) {

        // This is a Local Class
        class HelloBuilder {
            public String buildHello() {
                return "Hello " + name;
            }
        }

        System.out.println(new HelloBuilder().buildHello());
    }
}

Note: Local Classes have access to “final” variables of the method.  Hence the method “buildHello()” has access to the “name” parameter.

Note: There is no such thing as a Local Interface though.

Local classes follow the rules that variables follow from a scope of usage perspective. So…

  • You cannot use the Local Class before it is declared. So the following is a compiler error:
public class SayHello {

    public void sayHello(final String name) {

       // ERROR as not yet declared/defined
       System.out.println(new HelloBuilder().buildHello());

       // This is a Local Class
        class HelloBuilder {
            public String buildHello() {
                return "Hello " + name;
            }
        }
    }
}
  • You cannot use it outside the code block it is declared in.  So the following is a compiler error:
public class SayHello {

    public void sayHello(final String name) {
        { // Adding dummy braces to demostrate scope.

            // This is a Local Class
            class HelloBuilder {
                public String buildHello() {
                    return "Hello " + name;
                }
            }
        }

        // ERROR as unreachable from here
        System.out.println(new HelloBuilder().buildHello());     
    }
}

Local Class Inheritance

Local Classes can inherit from regular global classes.  So the following is valid.

class MyClass {

    public void doSomething() {

        class LocalClass extends Thread {
            public void run() {
                // Do Something
            }
        }

        new LocalClass().start();
    }
}

Within the scope of the code block, you could have multiple Local Classes inheriting from each other as below:

class MyClass {

    public void doSomething() {

        class LocalClass1 {
            public void run() {
                // Do Something
            }
        }

        class LocalClass1 extends LocalClass2 {
            public void run() {
                // Do Something
            }
        }
    }
}

[TBD]

Where should you use Local Classes?

Can’t help you quite yet.  Do share your thoughts by commenting. Here is an interesting sample though:

public class SayHello {

    // FOLLOWING DOES NOT USE LOCAL CLASSES

    public String sayHelloWithoutLocalClasses(final String name, Language lng) {

        switch (lng) {
        case FRENCH:
            return "Bon Jour " + name;
        case ENGLISH:
        default:
            return "Hello " + name;
        }
    }

    // FOLLOWING USES LOCAL CLASSES

    public String sayHelloWithLocalClasses(final String name, Language lng) {
        return getHelloBuilder(lng).buildHello(name);
    }

    private interface IHelloBuilder {
        String buildHello(String theName);
    }

    // Factory Method to return Hello Builder
    private IHelloBuilder getHelloBuilder(Language lng) {

        // This is a Local Class
        class EnglishHelloBuilder implements IHelloBuilder {

            @Override
            public String buildHello(String theName) {
                return "Hello " + theName;
            }
        }

        // This is a Local Class
        class FrenchHelloBuilder implements IHelloBuilder {

            @Override
            public String buildHello(String theName) {
                return "Bon Jour " + theName;
            }
        }

        switch (lng) {
        case ENGLISH:
            return new EnglishHelloBuilder();
        case FRENCH:
            return new FrenchHelloBuilder();
        default:
            return new EnglishHelloBuilder();
        }
    }

    public static void main(String[] args) {

        SayHello sayHello = new SayHello();
        sayHello.sayHelloWithLocalClasses("Ranjan", Language.ENGLISH);
        sayHello.sayHelloWithLocalClasses("Ranjan", Language.FRENCH);
        sayHello.sayHelloWithoutLocalClasses("Ranjan", Language.ENGLISH);
        sayHello.sayHelloWithoutLocalClasses("Ranjan", Language.FRENCH);

    }
}

Leave a comment