Novità in Java 1.6

Questi spunti sono presi dalla guida di html.it su java 1.6

2 Overload di metodi

Prima di Java 1.5 non esisteva un meccanismo per definire un numero di argomenti indefinito.
Il cosiddetto varargs (Variable Arguments), introdotto a partire dalla versione 1.5, aggiunge un nuovo modo per poter sopperire alla mancanza di questa caratteristica. Attraverso l'utilizzo del modificatore … (puntini sospensivi o ellipsis) è possibile definire la presenza di un numero variabile di argomenti.

public class Prodotto
{
  private int id;
  //...
  public Prodotto(int id, String... desc)
  {
    //...
  }

Ciò significa che il metodo si aspetta 0 o N parametri di tipo String da utilizzare in dipendenza della logica del metodo (o del costruttore, come in questo caso). Dal punto di vista della macchina virtuale è come definire un metodo che si aspetta una array di String.

La reale novità sta nel come attraverso varargs è possibile chiamare i metodi:

...// con varargs
metodoX(1,"uno","due","tre")
 
...//senza
metodoX(1,new String["uno","due","tre"])

Ecco come usare implementare il metodo

 public void testVarargs(String... list)
  {
    System.out.println("Metodo 1");
    for (String tmp:list)
    {
      System.out.println("#"+tmp);
    }
  }

4 Introduzione a Java Annotations

Possiamo definire un'annotation come un appunto che mettiamo per specificare qualcosa relativo al codice che stiamo scrivendo, un attributo particolare, un metodo o una classe che hanno delle peculiarità. Attraverso questo meccanismo siamo capaci di dare espressività al codice, di renderlo più leggibile agli occhi di altri sviluppatori ma soprattutto agli occhi del compilatore.

Le annotations, infatti, sono delle annotazioni per il compilatore (o per chi si occupa del deploy dell'applicazione) che, attraverso di esse avrà la possibilità di effettuare determinate operazioni.

Questo paradigma, oltre a rendere più espressivo il codice sorgente, permette una migliore manutenzione dello stesso. Utilizzando le opportune annotations, infatti, riusciremo ad evitare possibili errori di compilazione, oppure, meglio ancora, potremo delegare a strumenti esterni la configurazione dell'applicazione che stiamo scrivendo (nell'ultima parte dell'articolo vedremo le annotations in ambiente enterprise).

La stessa Sun definisce gli usi delle annotazioni come di seguito:

* Per informare il compilatore
* Per processare a tempo di compilazione (o di deploy)
* Per processare a run time

Le ultime due caratteristiche sono tipiche degli ambienti enterprise, che le possono utilizzare mediante reflection.

@Autore(
  name = "Pasquale Congiustì",
  company = "HTML.it"
)
class ClasseAnnotata() {
  ...
}

Ogni annotazione si presenta con il simbolo @ seguito dal nome dell'annotazione. Eventualmente può essere valorizzata con dei valori, tra parentesi tonde come coppia nome-valore. Essa precede la classe, il metodo o l'attributo che vogliamo annotare.

In questo esempio abbiamo annotato la classe con l'annotation Autore ed i due attributi name e company.

Nella prossima lezione vediamo le Annotations di default, fornite a partire dalla distribuzione J2SE 1.5. Si tratta di tre semplici annotazioni utili al compilatore.

Attenzione: utilizzare le annotazioni significherà che il codice non può essere compilato (e spesso anche eseguito) con versioni Java precedenti.

5 Tipi di Annotations

@Deprecated

L'annotazione @Deprecated viene utilizzata per specificare che l'elemento indicato è un elemento deprecato, cioè, attivo (per mantenere retrocompatibilità) ma non consigliato perché rimpiazzato da uno nuovo e supportato.

public class TestDeprecated {
  @Deprecated
  public void metodoA() {
    System.out.println("Questo metodo è DEPRECATO, usa metodoB().");
  }
 
  public void metodoB() {
    System.out.println("Questo metodo è SUPPORTATO.");
  }
}

La compilazione di questa classe non darà alcun segnale, procederà tutto normalmente. Sarà la compilazione della classe che userà TestDeprecated a ricevere segnalazioni di warning dal compilatore quando viene utilizzato il metodo metodoA().

@Override

L'annotation @Override è probabilmente la più utile in quanto consente di evitare degli errori, che in fase di codifica spesso accadono. L'annotazione dice che l'elemento indicato è un elemento che fa l'override (sovrascrive) del relativo elemento, del genitore da cui eredita.

class A{
  void metodo1(){
    System.out.println("Metodo 1");
  }
}
 
class B extends A{
  @Override
  void metodoo1(){
    System.out.println("Override A.metodo1()");
  }
}

Il compilatore da errore perchè è presente un errore di battitura nel metodo

@SuppressWarning

L'annotazione @SuppressWarning è utile quando vogliamo sopprimere le indicazioni di warning da parte del compilatore, ad esempio, perché stiamo usando dei metodi deprecati.

@SuppressWarnings({"deprecation"})
  public void usaMetodoDeprecato() {
   TestDeprecated t = new TestDeprecated();
   t.metodoA();
  }

Pur usando dei metodi deprecated, al compilatore abbiamo segnalato di sopprimere i warning.

Creare e utilizzare nuove annotazioni

JDK 5 permette allo sviluppatore di definire delle proprie annotazioni totalmente customizzabili. Si tratta semplicemente di definire il nome dell'annotazione e di alcune proprietà che la contraddistinguono.

La cosa che rende le annotations uno strumento davvero importante, tanto da alterare il tipico paradigma di programmazione, è la possibilità di effettuare introspezione del codice.

Con la reflection è possibile valutare a runtime quali annotations sono presenti (e quali valori hanno in esse) e quindi effettuare determinate operazioni. Possiamo pensare ad un framework che gestica la persistenza con un database, dove all'interno del codice sono presenti delle annotations che indicano come mappare attributi di classe su colonne di database. Oppure utilizzare uno strumento personalizzato per team di sviluppo per commentare opportunamente il codice, chi ne modifica i metodi, chi li crea e quando e così via, per mantenere traccia del lavoro svolto.

Dove usare le annotazioni

È chiaro come l'utilizzo opportuno di annotation sia capace di dare tanta espressività in più al codice prodotto. Il reale vantaggio che si ha è quando tale strumento viene affiancato da altri strumenti che fanno introspezione del codice e, in base ad esso, creano delle configurazioni per framework.

È proprio in queste situazioni, infatti, che le annotations hanno un notevole vantaggio. Prima citavamo il framework per la persistenza automatizzata, è il caso di Hibernate, che permette di mappare classi e tabelle attraverso descrittori XML. Ora, attraverso l'uso di annotation, non sarà più necessario creare dei descrittori di configurazione, bensì, adottare delle annotazioni che suggeriscano l'associazione direttamente all'interno del codice.

Mantenere descrittori di configurazione opportunamente allineati può essere un problema, in quanto si tratta di file esterni (generalmente XML), difficilmente leggibili dall'occhio umano.

È il caso anche degli EJB 3.0 che, dalle annotazioni, traggono un notevole vantaggio, rendendo più veloce e meno incline ad errori la produzioni di logica applicativa enterprise.

Creare e utilizzare nuove annotazioni

Questa parte viene da questo link

Creeremo una semplice annotazione con alcuni campi e vedremo anche come leggerla a runtime.

Crea e legge un'annotazione

package it.html.annotations;
 
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Una semplice annotation, usata per segnare gli elementi
* (classe, attributo, metodo), l'autore di quell'elemento e
* l'azienda.
*/
 
@Retention(RUNTIME)
public @interface MyAnnotation {
  public String value();
  public String author();
  public String company() default "HTML.it";
}

L'annotazione viene creata con il comando @interface, seguito dal nome dell'annotazione stessa. Badate che si tratta di classi java, pertanto esse seguono le stesse regole relative a package e import.

L'annotazione è (nel nostro caso) preceduta da un'altra annotazione, @Retention, che specifica il livello di introspezione desiderato. Ne esistono tre: RUNTIME, CLASS e SOURCE.

Bisogna usare RUNTIME se si vuole che l'annotazione sia utilizzabile dalla JVM, durante l'esecuzione (a runtime, appunto). Bisogna usare CLASS se si vuole che l'annotazione sia visibile solo dal compilatore. Bisogna usare SOURCE se l'annotazione non deve essere visibile (quindi usata meramente come commento al codice sorgente).

Il corpo dell'annotation può contenere, o meno, delle proprietà. Nel secondo caso si parla di marker annotation, utilizzate per marcare uno specifico elemento. Il primo caso è quello che ci riguarda e, come vediamo dall'esempio, è molto simile a quanto si fa con le interfacce.

Noi abbiamo definito tre parametri, tutti e tre stringa nominati: value, author e company.

I tipi che possono essere utilizzati sono i tipi primitivi (i numeri), le stringhe, enum, class, altre annotazioni ed array dei tipi appena menzionati. Una possibilità è quella di definire dei valori di default, come abbiamo fatto nel caso del parametro company.

Ultima cosa da dire, prima di utilizzare l'annotazione appena creata, è che c'è la possibilità di creare le annotazioni per specifiche parti della classe. L'annotazione può essere creata avendo come target solo i metodi, oppure solo i costruttori. Potrebbe avere come target solo la classe o i suoi attributi. In tal caso si usa un'altra annotation, @Target, che specifica appunto il tipo per cui l'annotation è stata pensata. Se avessimo voluto utilizzarla avremmo dovuto scrivere:

@Retention(value=RUNTIME)
@Target(value=XYZ)
public @interface MyAnnotation{
  ...

Dove il valore XYZ doveva essere rimpiazzato con: TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE. Tutto dipende dal fatto di voler forzare un'annotazione ad uno specifico tipo.

Andiamo a vedere una classe che viene "annotata" attraverso l'annotazione appena creata.

package it.html.annotations;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
 
//Qui la usiamo a livello di classe
@MyAnnotation(value="class",author="Pippo")
public class SimpleAnnotationUse {
  //qui, a livello di attributo
  @MyAnnotation(value="attribute",author="Pippo")
  public String saluto;
 
  //qui, a livello di costruttore
  @MyAnnotation(value="costruttore",author="Pippo")
  public SimpleAnnotationUse(){
    this.saluto="Hello World!";
  }
 
  //qui, a livello di metodo
  @MyAnnotation(value="method",author="Zio Paperone",company="Gugol")
  public String getSaluto(){
    return saluto;
  }
...
}

Possiamo vedere che ogni elemento della classe (e la classe stessa) vengono annotati con il valore indicante l'elemento stesso, il nome dell'autore e l'azienda (laddove l'azienda manca, verrà recuperato il valore di default).

Classe che fa introspezione della classe, dei metodi e degli attributi

public static void main(String args[]) throws NoSuchMethodException, NoSuchFieldException{
  System.out.println("Working Annotations...");
 
  //Accesso alla classe
  Class<SimpleAnnotationUse> c = SimpleAnnotationUse.class;
 
  //Mostra annotazioni
  System.out.println("Annotazione di classe: ");
  System.out.println(c.getAnnotation( MyAnnotation.class ));
 
  //Metodo costruttore
  Constructor<SimpleAnnotationUse> constructor = c.getConstructor((Class[]) null);
  System.out.println("Annotazione costruttore: ");
  System.out.println(constructor.getAnnotation(MyAnnotation.class));
 
  //Metodo getSaluto
  Method method = c.getMethod( "getSaluto" );
  System.out.println("Annotazione metodo getSaluto(): ");
  System.out.println(method.getAnnotation(MyAnnotation.class));
 
  //Campo saluto
  Field field = c.getField("saluto");
  System.out.println("Annotazione attributo saluto: ");
  System.out.println(field.getAnnotation(MyAnnotation.class));
}

Il main proposto fa introspezione della classe, dei metodi e degli attributi, utilizzando il metodo getAnnotation(). In questo caso stamperemo semplicemente il valore, ma i casi d'uso che si aprono sono veramente innumerevoli.

Salvo diversa indicazione, il contenuto di questa pagina è sotto licenza Creative Commons Attribution-ShareAlike 3.0 License