It might be redundant at times but it can be very convenient and fast.
For example the way I set up gears here:

How well does Blender Rigid Body physics translate to real life
I choose to not drive the gears directly because it enables me to quickly synchronize them so the teeth match. I don't know a faster way. I could have tried to adjust it with the fcurve itself, I could have used another variable. Instead I just rotate the child gear a bit without ever changing the driver. It's easier to create any kinds of offsets.
Sometimes I just don't want my object origin at the center of rotation. And sometimes I want a nice and regular spin around an axis that has no notion of aligning itself to the local axes of the object. Call me difficult.
Another example:

How do you animate the Inception spinning top?
Empties are useful to single out an axis. Imagine the earth. It's spinning, but it has a tilted axis AND it is also precessing, the axis itself is rotating plus maybe a tilted orbit. If you give those movements their single axes, it's much clearer which part does what (you can label them in the 3D-view) instead of diving into fcurves and having to remember rotation orders. Less math knowledge needed. In team projects it's a good thing to keep things transparent in case someone else has to take over.
Easy to use and easy to understand sometimes beats the most elegant and compact but obscure way.
m.ardito's point is strong, too.