Chapter 8 - Java for Beginners Course

Anonymous Classes

In certain scenarios, we might want to define an implementation of an interface or a subclass without having to create a whole new class and Java file.

Anonymous classes allow us to both define a class and create an instance of it at the same time. These classes, as expected, don’t have a name and you can’t use them more than once.

Let’s use our filter example as a guide.

In our previous example, we defined a Filter<Integer> as follows:

Filter<Integer> filterToUse = new GreaterThanFiveFilter();

And this is fine, we defined our GreaterThanFiveFilter as a named class and we’re instantiating it here.

We could achieve the same with an anonymous class as shown below:

Filter<Integer> filterToUse = new Filter<Integer>() {
    @Override
    public boolean filter(Integer element) {
        if (element > 5) {
            return true;
        }
        return false;
    }
};

Here, we’re both:

  1. Defining an anonymous class via the new Filter<Integer>() { …​ } statement, and inside the braces we implement the methods defined in the Filter interface, in our case, only the filter method.

  2. And, as we’re using the new keyword, creating an instance of that anonymous class and assigning it to the filterToUse variable.

Both classes, the GreaterThanFiveFilter and our anonymous class provide the same logic and we could choose to use one or the other.

Our example with the anonymous class

Using the new approach, our example code would look as follows:

In the example code run the JavaListWithAnonymousFilterApp
public static void main(String[] args) {
    // our input list of numbers
    List<Integer> numbers = Arrays.asList(1, 2, 3, 10, 11, 12, 0);

    // define the filter we want to use as an anonymous class
    Filter<Integer> filterToUse = new Filter<Integer>() {
        @Override
        public boolean filter(Integer element) {
            if (element > 5) {
                return true;
            }
            return false;
        }
    };

    // call our new `filterNumbers` static method to do the filtering
    List<Integer> filtered = filterNumbers(numbers, filterToUse);

    // print out the filtered list
    for (Integer number : filtered) {
        System.out.println(number);
    }
}

private static List<Integer> filterNumbers(List<Integer> numbers, Filter<Integer> filterToUse) {
    List<Integer> filtered = new ArrayList<>();
    // filter the list using the provided `filterToUse`
    for (Integer number : numbers) {
        if (filterToUse.filter(number)) {
            filtered.add(number);
        }
    }
    return filtered;
}

Output:

10
11
12

Access to local variables from the enclosing scope and class

Anonymous classes have direct access to variables in the enclosing scope and class as follows:

  1. Local variables (as in, the ones declared in methods) as long as they’re final (using the final keyword explicitly) or they’re effectively final (the final keyword isn’t used but their value isn’t assigned more than once).

  2. Member variables in the enclosing class.

For example, let’s assume that in our example filter we want to specify the minimum value using a local variable instead of setting it to 5 directly (for example, maybe we want the user to define it). In that case, we could do the following:

In the example code run the JavaListWithAnonymousFilterAndLocalVarApp
//...

final int minimum = 10;

// define the filter we want to use as an anonymous class
Filter<Integer> filterToUse = new Filter<Integer>() {
    @Override
    public boolean filter(Integer element) {
        if (element > minimum) {
            return true;
        }
        return false;
    }
};

//...

Output:

11
12

Here, you can see that the anonymous class is reading the value of the local variable minimum that is outside the anonymous class' scope.

When should anonymous classes be used?

There is no hard-rule, but in general use them when the anonymous class you’re defining is only meant to be used once and is closely related to the class where it will be defined.

If you need to re-use the anonymous class in several places, you’ll be better off having a named class rather than redefining the anonymous class in multiple places in your code.