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.

Code in GitHub

Get the code for this tutorial using the links below.

Project Repo
Download code for this step
Main class for this step
Dependencies

This is a list of recommended tutorials or courses that might be useful before starting this one.

Contents
Welcome to the Course!
Course Introduction
Chapter 1 - Building Blocks
Quick introduction to Java Variables Classes And Objects Class Example - Defining a class Object Examples - Creating instances Java Application Example - Running our first app Accessing class members - The dot operator Packages - Organizing the code
Chapter 2 - Primitives and Operators
Primitives Arithmetic Operators Assignment Operator Unary Operators Equality and Relational Operators Conditional Operators
Chapter 3 - Statements and Control Flow
Expressions Statements If-Then Statement If-Then-Else Statement More If Statements Switch Statement While and Do-While Statements For Statement Branching Statements Exception Handling
Chapter 4 - Code Example
Example Project - A Simple Vending Machine Adding money Delivering Items Giving Change
Chapter 5 - Classes and Interfaces
Introduction Access Level Modifiers Class Declaration - Class, Methods and Fields Class Declaration - Constructors Inheritance Basics Inheritance - Constructors Inheritance - Methods and Fields Polymorphism Abstract Classes and Methods Interfaces Static Class Members Class Composition Final Classes and Class Members Generic Classes
Chapter 6 - Base Object Behaviors
Introduction Type Comparison Type Casting Object Equality - The Contract Object Equality - Common Pitfalls Object String Representation Garbage Collection Object Comparison Primitive Wrappers and Autoboxing
Chapter 7 - Data Structures
Introduction Arrays - Declaration and Creation Arrays - Basic Operations Core Collection Interfaces List and ArrayList - Basic Operations ArrayList Internals Introduction to Hash Tables Map and HashMap - Basic Operations Set and HashSet - Basic Operations
Chapter 8 - Anonymous classes and lambdas
Introduction Filtering a List Anonymous Classes Lambdas Built-in Functional Interfaces
Chapter 9 - Streams
Introduction Creating Streams Intermediate Operations Terminal Operations