3 coisas que você não sabia sobre as anotações em Java

Quem desenvolve aplicações usando a linguagem Java quase certamente conhece as anotações.
Por exemplo, considere a classe de um serviço hipotético abaixo:
@NotThreadSafepublic class MeuServico { ...}
À classe foi adicionada a anotação NotThreadSafe
.
Ela indica que o serviço não é "thread-safe".
Em outras palavras, não é seguro que threads distintas acessem o serviço simultaneamente.
É importante notar que, por si só, a anotação nada faz; apenas adiciona à classe a informação de que ela não é thread-safe.
Por outro lado, um framework, por exemplo, pode utilizar esta informação para, em tempo de execução, restringir ou sincronizar o acesso a este serviço.
Neste post falo sobre 3 coisas que talvez você não sabia sobre as anotações Java.
Bora lá.
1. Anotações são apenas modificadores
Sintaticamente falando, anotações são apenas modificadores.
Para entender considere o método toString
abaixo:
@Overridepublic final String toString() { return "Anotações são apenas modificadores";}
Saiba que, para o compilador Java, a anotação é apenas mais um modificador do método.
Então a forma seguinte também é valida:
public @Override final String toString() { return "Anotações são apenas modificadores";}
Ou, se preferir, esta outra:
public final @Override String toString() { return "Anotações são apenas modificadores";}
As três formas são equivalentes em termos de sintaxe.
Vale notar, no entanto, que a primeira forma é a recomendável. Principalmente quando a anotação refere-se ao método.
A terceira forma pode ser usada caso a anotação refira-se ao tipo de retorno do método.
Em resumo, prefira as formas idiomáticas da linguagem.
2. Anotações de tipo e nomes completos qualificados
No item anterior eu mencionei anotações de tipo. Não entrarei em detalhes sobre o que sejam as anotações de tipo, está fora do escopo deste post.
Basta saber que, no exemplo abaixo, as anotações Foo
e Bar
referem-se aos tipos e não ao campo.
public class Exemplo01 { public @Foo String a; public @Bar LocalDate b;}
Em outras palavras, a anotação Foo
adiciona informação ao tipo String
e não ao atributo a
.
De modo similar, Bar
adiciona informação ao tipo LocalDate
e não ao atributo b
.
Suponha que, por um motivo qualquer, você tenha que se referir aos tipos por seus nomes completos qualificados. Isto é, por algum motivo, você tenha que escrever:
public class Exemplo02 { public java.lang.String a; public java.time.LocalDate b;}
E agora você precisa anotar os dois tipos com Foo
e Bar
respectivamente.
Saiba que o exemplo seguinte não compila:
// erro de compilação!public class Exemplo02 { public @Foo java.lang.String a; public @Bar java.time.LocalDate b;}
Para corrigir o erro de compilação é necessário fazer:
public class Exemplo02 { public java.lang.@Foo String a; public java.time.@Bar LocalDate b;}
Ou seja, a anotação vem imediatamente antes do nome simples do tipo.
Sabia dessa?
3. Anotações de tipo e arrays
Considere o campo a
da classe seguinte:
public class Exemplo01 { public int[][] a;}
O seu tipo é um "array de array de ints", correto?
Temos, então, três tipos:
-
int[][]
- array de array de ints -
int[]
- array de ints -
int
- ints
É possível, então, anotar cada um desses tipos individualmente.
public class Exemplo02 { public @C int[][] a; public int @A [][] b; public int[] @B [] c;}
Ou anotar dois dos tipos:
public class Exemplo03 { public @C int @A [][] a; public int @A [] @B [] b; public @C int[] @B [] c;}
Ou anotar os três tipos:
public class Exemplo04 { public @C int @A [] @B [] a;}
Mas qual tipo exatamente está sendo anotado? Em todos os exemplos:
-
anotação
A
anota o tipoint[][]
-
anotação
B
anota o tipoint[]
-
anotação
C
anota o tipoint
Até o próximo artigo
Por hoje é isto. Espero que tenha gostado.
O código para todos os exemplos pode ser encontrado no GitHub.
Se tiver comentários, dúvidas ou correções sobre este post, por favor, envie um email.