Annotations do not have a performance win... unless they are used by a code generation step to inject code for you (article).
Where Annotations do have a definite win is with the concept of auto-configuration, which is the first killer feature exploited by Spring and similar frameworks.
Annotations improve over the prior legacy solutions:
- Marker interfaces--requires a class to "implement" an interface without any methods defined. Used for reflection based configuration in the past.
- Configuration files--requires the user to know the fully qualified class names. This is what Spring configuration used to look like, along with Enterprise JavaBeans (EJB).
- Javadoc plugins--before annotations were officially implemented, some esoteric programs used the
javadoc
tool to do what annotations do now. The chief downside is that javadoc markers cannot be reflected at runtime, and you have to use another tool to preprocess your source code before compiling.
There may have been others, but these are the three legacy solutions I am personally familiar with. Annotations are a set of tools that can enable solutions without being overly invasive to your code.
One more use that popped in my head that annotations replaces was for reflection based decision making--most notably with testing. JUnit used to require you to extend a TestCase
base class and name all your test methods with the prefix test
.
Example legacy JUnit test:
public class SomeCoolTestCase : TestCase {
public void testSomethingCool() {
assertEquals(5, 2+2);
}
}
All the assert methods were defined in the base class, and if your test prefix was misspelled the test wasn't run. I.e. tsetSomethingCool()
wouldn't have a compile error, but also wouldn't run.
Annotations and static imports handled both cases where your unit tests weren't constrained by these conventions anymore. The annotations fixed the problem where your method was misnamed, so your compiler will fail if you misspell the annotation name. They also made the pre/post test functions more flexible like that. Static imports fixed the problem of the assert
functions being in a base class, so you can access them as if they were part of your test.
Example modern JUnit test:
import static junit.framework.Assert.*;
@TestCase
public class SomeCoolTestCase {
@Test
public void givenSomethingCool_shouldBeEqual() {
assertEquals(5, 2+2);
}
}
NOTE: sorry for the math joke in both the failing tests... Code was pulled from memory, so some changes would likely be needed to compile.