SimpleDateFormat: quante insidie

JavaProprio qualche giorno fa mi trovavo a parlare della proprietà lenient della classe SimpleDateFormat, cioè un booleano che, se lasciato al valore di default, permette di riconoscere come “date ben formate” giorni come il 31 febbraio 2012 o cose del genere. Ma le insidie dietro questa classe sono altre, e molto più gravi.

Leggendo la documentazione della classe si trova il seguente commento:

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

Ebbene, quelli della Oracle consigliano di creare delle istanze separate della classe per ogni thread che la usa. Ma cosa succede se non si segue questo consiglio ?

Ho cercato un po’ su google e ho trovato degli esempi di codice multithread che utilizzano una variabile statica di tipo java.text.SimpleDateFormat, ne riporto uno di seguito:

static SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy");
static String testdata[] = { "01-01-1999", "14-02-2001", "31-12-2007" };

public static void main(String[] args) {
Runnable r[] = new Runnable[testdata.length];
for (int i = 0; i < r.length; i++) {
final int i2 = i;
r[i] = new Runnable() {
public void run() {
try {
for (int j = 0; j < 1000; j++) {
String str = testdata[i2];
String str2 = null;
/* synchronized(df) */{
Date d = df.parse(str);
str2 = df.format(d);
}
if (!str.equals(str2)) {
throw new RuntimeException(
"date conversion failed after " + j
+ " iterations. Expected "
+ str + " but got " + str2);
}
}
} catch (ParseException e) {
throw new RuntimeException("parse failed");
}
}
};
new Thread(r[i]).start();
}

}

Il codice è molto semplice: ci sono tre date (“01-01-1999”, “14-02-2001” e “31-12-2007”) e diversi thread in concorrenza prendono una data in formato stringa, la trasformano in java.util.Date e poi la riconvertono in stringa, generando un’eccezione nel caso in cui le stringhe non corrispondano.

Non ci volevo credere, se si lancia il programma si ottiengono errori come:

Exception in thread "Thread-2" java.lang.RuntimeException: date conversion failed after 0 iterations. Expected 14-02-2001 but got 01-02-1999
at it.nerdammer.sdf.SimpleDateFormatTest$1.run(SimpleDateFormatTest.java:27)
at java.lang.Thread.run(Thread.java:680)

Cioè, a partire da tre date possibili, l’oggetto SimpleDateFormat ne ha creata un’altra: 01-02-1999. E’ assurdo che, invece di lanciare un’eccezione in caso di accesso concorrente, la classe restituisca delle date a casaccio !

Il risultato è che se un programmatore non è a conoscenza di questo fatto, e credo che un buon 50% dei programmatori Java non lo conoscano, ci si accorgerà del problema sicuramente troppo tardi !

Un pensiero su “SimpleDateFormat: quante insidie”

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *