Let’s say you’re writing a class and at some point you need to spawn
off some work in a different thread. A common solution is to have your
class implement Runnable
and pass yourself to the Thread
constructor:
class Something implements Runnable {
public void doSomething() {
new Thread(this).start();
}
@Override // Runnable
public void run() {
// Do work.
}
}
The trouble with that approach is that you’ve advertised
to the world that your class is runnable, and you’ve let them call
your run()
method, but that’s no one’s business but yours. You’re
not really runnable from their point of view. You’ve given them
incorrect information and too much power.
It’s even worse to subclass Thread
, since you’ve blown your only
chance to subclass something else, and you’ve completely lost control
over your thread, which anyone else can now manipulate or destroy.
Pass in an anonymous class instead, and have it call a private method:
class Something {
public void doSomething() {
new Thread(new Runnable() {
@Override // Runnable
public void run() {
doWork();
}
}).start();
}
private void doWork() {
// Do work.
}
}
This is even easier with lambdas:
class Something {
public void doSomething() {
new Thread(this::doWork).start();
}
private void doWork() {
// Do work.
}
}
This sends no incorrect message
to onlookers, prevents them from calling your run()
method
at the wrong time or in the wrong thread, allows you to
give your function a better name (doWork()
vs. the generic run()
),
and allows you to pass parameters to your method:
class Something {
public void doSomething(final int count) {
new Thread(() -> doWork(count)).start();
}
private void doWork(int count) {
// Do work.
}
}
This isn’t possible when passing yourself as an implementer of the interface. Though you could get around that with fields, using fields as globals is a bad idea (see Avoid fields for communication between methods).
Similarly, only implement Future
, Callable
, ThreadFactory
,
Executor
, MouseListener
, and other similar interfaces,
if you really want other classes to treat you as such. Don’t do it just as
a way to have a method (such as addMouseListener()
) call one of
your methods as a callback.