Annotations are a very useful and even necessary tool, especially when building complex applications using libraries, like Room for databases, or frameworks like Spring Boot for backend. Having said that, let's look into the basics of annotations and consider some examples.
Annotation
Annotations offer a way of providing instructions and metadata (data about data) to the compiler, IDE, or framework to handle some complex tasks and make your life easier. This information may be intended just for the IDE to help you write more efficient code or may contain documentation for both yourself and the compiler about some piece of code.
Metadata is the information about data that makes this data more meaningful, so in our case, the compiler or frameworks will have useful information about our code to perform complex tasks.
The most common case is using libraries like Room or Retrofit when you develop android apps or frameworks like Spring or Spring Boot. These frameworks come with many built-in annotations, and through them, frameworks will know what you want to do and will do it for you without showing you the complex implementation. You may conceive of an annotation as magic – one word does a lot of work in the background.
In code, it may be any word starting with the @ symbol, which we put directly above the specific target or before it. For example, if we want to apply an annotation @MyAnnotation to some class MyClass, we will do it like this:
// Before the code line
@MyAnnotation class MyClass {}
// Or directly above it
@MyAnnotation
class MyClass {}
Annotations will be applied to the closest element as in the example below:
@Suppress("CanBeVal")
var myFirstName = "Alex" // Suppress annotation will be applied here
var myFriendName = "Aaron" // will NOT be applied here
You can add as many annotations as you want to one target, like in the example below:
//We applied two annotations to one field, and it's totally ok
@NotNull
@PrimaryKey(autoGenerate = true)
var taskId: Long = 0LSuppress annotation
When writing code, you've probably already seen IDE warnings about code style – for example, about using magic numbers. Is it annoying? It is, so let's learn our first annotation – @Suppress – which will suppress such warnings.
@Suppress("name of warning") is an annotation that tells the compiler to suppress a specific warning, which is passed in quotation marks in the parentheses.
In the example below, the variable myNumber should be val rather than var, as it is never modified, so the IDE will warn you about it and suggest replacing it.
fun main() {
var number = 5
println(number)
}
Ok, thanks! But what if you want to keep it var for specific reasons and avoid any warnings? Now we will apply @Suppress() like in the code snippet below:
fun main() {
@Suppress("CanBeVal") var number = 5
println(number)
}
No warnings now!
Annotation target
Annotation targets are all kinds of annotated elements, such as classes, functions, properties, and expressions. Some annotations can work with specific elements, and some can work with all elements, so it's important to know the target if you are creating a custom annotation or using them. We will learn how to create those in the following topics.
Now, let's again use @Suppress() to target warnings on different elements.
In the example below, it will work on only one statement – the one directly below the annotation or beside it.
fun main() {
@Suppress("CanBeVal")
var number = 45 // Warning will disappear from here
var anotherNumber = 5 // Warning will still appear here
println(number)
println(anotherNumber)
}
We can also target a whole function. Consider the example below:
// no warning at all!
@Suppress("CanBeVal")
fun main() {
var number = 45
var anotherNumber = 5
println(number)
println(anotherNumber)
}
Also, we can target a whole class, like in the example below.
@Suppress("unused") will suppress any warning about the unused elements.
// Zero warnings
@Suppress("unused")
class MyClass {
fun printNumber() {
/*..*/
}
fun sumNumber() {
/*..*/
}
}
Last but not least, we can target a whole file by writing @file:NameOfAnnotation() at the top of the file.
@file:Suppress("unused")
class MyClass {
fun printNumber() {
/*..*/
}
fun sumNumber() {
/*..*/
}
}
class AnotherClass {
fun printNumber() {
/*..*/
}
fun sumNumber() {
/*..*/
}
}
If you want to suppress warnings about a variable, you should write "UNUSED_VARIABLE" instead of "unused".
In fact, you can target even more elements with @Suppress, you can see the whole list in the official documentation.
Conclusion
In this topic, we have learned that annotations are a way of providing metadata about code to the IDE, compiler, yourself, or a third party tool like Spring or Spring Boot. They are intended to handle complex tasks and help you easily write efficient code. Also, annotations have specific targets to work with. You've learned how to work with annotations using the @Suppress example. Let's have some practice now.