As you may have noted, in much of our recent work, we’ve ended up creating classes that (a) are used by only one other class or (b) are effectively used only once. For example,
For those used to functional programming, the first two issues
suggest that we might use anonymous functions. For example, in
Scheme, to select all the values less than 10 in a list
of numbers, we might write (list-select numbers (lambda (val)
(< val 10)))
or (list-select numbers (r-s < 10))
.
Java (at least Java up through version 7) does not include functions as a first-class data type, so it’s unlikely that we’d have anonymous functions in Java. However, in version 1.1, Java introduced anonymous classes, which can help serve the same purpose. In this reading, we explore the usage of anonymous inner classes.
While we will eventually explore anonymous inner classes in the context of predicates, comparators, iterators, and more, let’s start with an invented situation that is simultaneously simpler and more complex than some of these examples.
At times, we want objects that can greet the user. We’ll call
such objects Greeter
s, and give them a simple interface.
import java.io.PrintWriter;
/**
* A very simple interface to be used in illustrating anonymous inner classes.
*/
public interface Greeter {
/**
* Print a greeting.
*/
public void greet(PrintWriter pen);
} // interface Greeter
Here’s a simple class that implements the Greeter
interface.
import java.io.PrintWriter;
/**
* A very simple example of a greeter.
*/
public class SampleGreeter implements Greeter {
public void greet(PrintWriter pen) {
pen.println("Hello world.");
} // greet
} // class SampleGreeter
Now, let’s try to think like Java designers. Sometimes, given an
object, we might want to make a greeter for that object. Why doesn’t
the object want to be its own greeter? Maybe we need more than one
greeter, and want each to behave differently, or at least independently.
(In case you couldn’t tell, we’re reflecting on iterators and
iterables, as well as some other paired interfaces.) We’ll call
things that generate greeters Greetable
s.
/**
* A very simple interface to be used in illustrating anonymous inner classes.
*/
public interface Greetable {
/**
* Get the greeter.
*/
public Greeter greeter();
} // interface Greetable
Here’s a simple implementation.
/**
* A very simple class that creates a Greeter.
*/
public class SampleGreetable1 implements Greetable {
@Override
public Greeter greeter() {
return new SampleGreeter();
} // greeter
} // interface SampleGreetable1
Greeter
objectsYou haven’t seen anything too surprising so far, or at least I hope
you haven’t. Now, let’s move a step further. Suppose we want to
create a new Greetable that returns a greeter that returns the
string “Hi!”. We could use the same technique as above. But we’re
creating a Greeter
class that only gets used once. What’s the
alternative?
The alternative is an anonymous inner class. Rather than writing
down the full class definition, we can use the keyword new
, the
interface name, and then the body of a class. That is,
import java.io.PrintWriter;
/**
* A simple class that builds an anonymous greeter.
*/
public class SampleGreetable2 implements Greetable {
@Override
public Greeter greeter() {
return new Greeter() {
@Override
public void greet(PrintWriter pen) {
pen.println("Hi");
} // greet(PrintWriter)
}; // new Greeter
} // greeter()
} // class SampleGreetable2
What’s going on here? It looks like we’re calling a constructor for
an interface, and we know that interfaces don’t have constructors.
There’s also an open brace after the new Greeter()
, rather than
a semicolon.
Welcome to the world of anonymous inner classes. If you use new
with
an interface (and, in some cases, with classes) and then follow it with
a code block, Java treats that as “I’m simultaneously describing a class
and building an object in the class.”
Are there any advantages to this approach? After all, it’s not
that much less code than in the previous example. The most obvious
benefit is that we’ve achieved fairly strong encapsulation - since
the class is within SampleGreetable2
, nothing else can access it.
We also have the normal benefit of anonymity - if the class is only
used here, there’s no need to come up with a name for it. But these
two reasons alone are not the only reasons we like anonymous inner
classes.
Often, when we build helper objects, like Greeter
objects or
Iterator
objects, they need to know something about the object
they are helping. That usually means we need to have the helper
object reference the object they are helping.
Once of the nice things about inner classes is that they can reference
the fields of the enclosing class without explicitly including it
as a field. In the following example, when we construct the
Greeter
, we copy and change a field in the enclosing class.
import java.io.PrintWriter;
/**
* A simple class that creates an anonymous greeter and references an internal
* field of the enclosing class during creation.
*/
public class SampleGreetable3 implements Greetable {
int i = 0;
@Override
public Greeter greeter() {
return new Greeter() {
int num = ++i;
@Override
public void greet(PrintWriter pen) {
pen.println("Number " + num);
} // greet(PrintWriter)
}; // new Greeter
} // greeter()
} // interface SampleGreetable3
Suppose we wrote the following.
PrintWriter pen = new PrintWriter(System.out, true);
Greetable g = new SampleGreetable3();
Greeter[] greeters = new Greeter[] {
g.greeter(), g.greeter(), g.greeter(), g.greeter(), g.greeter()
};
for (int i = 0; i < greeters.length; i++) {
pen.print(i + ": ");
greeters[i].greet(pen);
} // for
Our output will be
0: Number 1
1: Number 2
2: Number 3
3: Number 4
4: Number 5
Of course, we could achieve the same effect by writing a separate
class and giving it a constructor that takes i
as a
parameter, but that’s a lot more coding.
But we’re not done yet! Not only can we reference the fields of an enclosing class when we build the inner class, we can even reference them when we run the method.
import java.io.PrintWriter;
/**
* A simple class that creates an anonymous greeter that references a field in
* the enclosing class at the time is built and at the time it greets.
*/
public class SampleGreetable4 implements Greetable {
int i = 0;
@Override
public Greeter greeter() {
return new Greeter() {
int num = ++i;
@Override
public void greet(PrintWriter pen) {
pen.println(num + " of " + i);
} // greet(PrintWriter)
}; // new Greeter
} // greeter()
} // interface SampleGreetable4
If we run code similar to the above, we’ll get
0: 1 of 5
1: 2 of 5
2: 3 of 5
3: 4 of 5
4: 5 of 5
Things are going pretty well. We can reference a field of the enclosing class when we build an object in an inner anonymous class. We can reference a field of the enclosing class when someone invokes the object’s methods. What else would we want to do? Well, if we are used to a functional model, we might even want to be able to reference a parameter or local variable in an enclosing method. For example, we might want to write something like the following:
Greeter makeGreeter(int n) {
return new Greeter() {
@Override
public void greet(PrintWriter pen) {
pen.println(n);
} // greet(PrintWriter)
}; // new Greeter
} // makeGreeter
However, if we try that, the Java compiler will greet us with a friendly message something like the following:
SampleGreetable5.java:19: error: local variable n is accessed from within inner class; needs to be declared final
pen.println(n);
^
1 error
What’s going on here? The Java compiler is worried that n
gets
referenced in a method that may be called when that method is no
longer in scope. (And we can be pretty sure that it won’t be in
scope when greet
gets called.) Some languages like Scheme have
a clever way of dealing with these issues. The designers of Java,
on the other hand, didn’t want to have to deal with those complexities.
Hence, Java is only willing to let you reference the parameter if
it knows that the parameter won’t change, in which case it can just
grab the current value. The final
modifier is how you tell Java
that it won’t change. With this update, we can write the following:
import java.io.PrintWriter;
/**
* A simple class with an extra method that creates an anonymous Greeter that
* references a parameter.
*/
public class SampleGreetable5 implements Greetable {
int i = 0;
@Override
public Greeter greeter() {
return makeGreeter(++i);
} // greeter()
Greeter makeGreeter(final int n) {
return new Greeter() {
@Override
public void greet(PrintWriter pen) {
pen.println(n);
} // greet(PrintWriter)
}; // new Greeter
} // makeGreeter
} // interface SampleGreetable5
You may have a chance to explore this particular issue in lab.
this
” mean?You’ll note that we have not been using this
in referencing
fields. That’s because this
can feel a bit ambiguous
for inner classes - does this
refer to the inner class
that we’re building or to the enclosing class? Let’s try updating
the 4th example to see what the Java compiler tells us.
public void greet(PrintWriter pen) {
pen.println(this.num + " of " + this.i);
} // greet(PrintWriter)
As you might expect, we get another helpful message.
SampleGreetable6.java:17: error: cannot find symbol
pen.println(this.num + " of " + this.i);
^
symbol: variable i
1 error
We’ve learned a lot from that message. The compiler didn’t complain
about this.num
, so it seems that this
refers to the inner class.
It did, however, complain about this.i
, and so this
does not
refer to the enclosing class. It turns out that to refer to the
enclosing class, you prefix this
with the class name.
import java.io.PrintWriter;
/**
* Explicit references to the location of various fields.
*/
public class SampleGreetable6 implements Greetable {
int i = 0;
@Override
public Greeter greeter() {
return new Greeter() {
int num = ++SampleGreetable6.this.i;
@Override
public void greet(PrintWriter pen) {
pen.println(this.num + " of " + SampleGreetable6.this.i);
} // greet(PrintWriter)
}; // new Greeter
} // greeter()
} // interface SampleGreetable6
At this point you may be saying to yourself “Cool! I can use this when working with predicates.” Or you may be asking yourself “How can I use this in practice?” (Guess what, one answer is “with predicates”.) So let’s do a quick exploration of why anonymous inner classes might be useful for predicates.
We’ll start with a sample use of predicates, printing all of the values in an array for which the predicate holds.
/**
* Print all the elements of the array for which pred holds.
*/
public static <T> void printMatching(PrintWriter pen, T[] vals, Predicate<T> pred) {
for (T val: vals) {
if (pred.test(val)) {
pen.println(val + " ");
} // if
} // for
pen.println();
} // printMatching(PrintWriter, T[], Predicate<T>)
Now, suppose we have an array of strings and want all of the short strings (say the strings of length less than or equal to 4). We could write something like the following:
Predicate<String> small = new Predicate<String>() {
@Override
public boolean test(String str) {
return str.length() <= 4;
} // test(String)
}; // new Predicate<String>
Now we can print the small strings in our test with something like the following.
java
printMatching(pen, essay, small);
`
That seems much easier than defining a whole new class, doesn’t it?
Like anonymous functions and named lets in Scheme, anonymous inner classes are powerful and convenient for experienced programmers and a bit overwhelming for novice programmers. Take it slowly, and you’ll soon find that anonymous inner classes will be a useful tool for many situations.
As we noted at the start of this reading, anonymous inner classes were added to Java long before things that resemble anonymous functions (“lambdas”, in common Java parlance). In a bit, you’ll learn about lambdas in Java and when they can and cannot be used to replace anonymous inner classes.
Most of this reading is closely based on a similar reading from fall 2014. I’ve reformatted the code and rewritten some text.
I did a bit more cleanup in Fall 2023.