Java 14 0.0.0.1
Java 14 preview della preview
Tra le varie JEP inserite per la JDK14, troviamo le seguenti:
305: Pattern Matching for instanceof (Preview) 361: Switch Expressions (Standard) 358: Helpful NullPointerExceptions 368: Text Blocks (Second Preview) 359: Records (Preview)
A parte la 358 che prevede che nel messaggio di errore della Null Pointer Exception sarà indicata la variabile che ha valore null (!!!!!),è da dire che sia la 305 sia la 361 sia la 359 sembrano indicare un lavoro volto forse a preparare la strada alle data classes di cui scrive Brian Goetz (Java Langua Architect) qui. Java subirà il fascino di Scala o di Kotlin?
Per ora esaminiamo nel dettaglio pattern matching per instanceof e switch expression e successivamente le altre.
Pattern matching per instanceof
La 305 di cui è autore proprio il nostro Brian Goetz, è finalizzata a trasformare il noto operatore “instance of” in modo tale che possa accettare non un Type ma un test type pattern (presente in F#) vale a dire un tipo ed una variabile di binding.
Per cui quanto di seguito:
Object s = …
if(s instance of String && ((String)s).length()> n )
{
String aString = (String s)
int l = s.length();
}
potrà essere scritto come:
Object s = …
if( s instanceof String aString && s.length() > n){
int l = s.length();
}
eliminando codice verboso.
Switch come espressione.
La 361 è relativa all’introduzione di switch come espressione e non più come statement. Le principali novità sono, quindi:
- La possibilità di adoperare più label nello stesso case
- Il case prevede la possibilità di adoperare il simbolo “->” e le parentesi graffe per eseguire blocchi di statement e impedisce di eseguire il blocco successivo nel caso in cui non sia presente il break
- E’ una espressione: restituisce un valore, per cui può essere passata in statement più grandi (e potenzialmente come argomento di una lambda expression)
- Il compilatore verifica che siano coperti tutti i possibili valori
- “Yield” restituisce il valore dell’espressione in un blocco.
Vediamone un’esempio (il codice è disponibile a questo link).
Nell’esempio in questione è presente un metodo che calcola il valore finale di una fattura in base al valore dei singoli items e al tipo di cliente: in base al tipo di cliente applica l’iva e applica degli sconti. Lo sconto non dipende solo dal tipo di cliente ma anche dall’ammontare della spesa.
Nel caso in cui si utilizzi lo statement switch, il codice è il seguente:
private Double computeFinalPriceOldWay(Customer customerType, List<Item> items)
{
Double totalPrice = items.stream().map(item -> item.getPrice()).reduce(0d, Double::sum);
Double vat = (totalPrice / 100 * STANDARD_VAT);
Double invoicePrice = null;
switch (customerType)
{
case SIMPLE:
invoicePrice = totalPrice;
break;
case BUSINESS:
case PRIVATE:
Double finalPrice = totalPrice + vat;
invoicePrice = finalPrice;
break;
case PRIVILIGED:
Double discount = (totalPrice / 100 * STANDARD_DISCOUNT);
Double finalPricePrivileged = totalPrice + vat - discount;
Integer finalPriceOver = (int) Math.round(finalPricePrivileged / 100d);
switch (finalPriceOver)
{
case 1:
invoicePrice = finalPricePrivileged;break;
case 2:
case 3:
case 4:
case 5:
case 6:
invoicePrice = finalPricePrivileged - (finalPricePrivileged / 100 * LOW_DISCOUNT);break;
default:
invoicePrice = finalPricePrivileged - (finalPricePrivileged / 100 * STRONG_DISCOUNT);
}
;
}
return invoicePrice;
}
Nel caso in cui si utilizzi il nuovo switch, come espressione il codice è il seguente:
private Double computeFinalPrice(Customer customerType, List<Item> items)
{
Double totalPrice = items.stream().map(item -> item.getPrice()).reduce(0d, Double::sum);
Double vat = (totalPrice / 100 * STANDARD_VAT);
Double invoicePrice = switch (customerType)
{
case SIMPLE -> {
yield totalPrice;
}
case BUSINESS, PRIVATE -> {
Double finalPrice = totalPrice + vat;
yield finalPrice;
}
case PRIVILIGED -> {
Double discount = (totalPrice / 100 * STANDARD_DISCOUNT);
Double finalPrice = totalPrice + vat - discount;
Integer finalPriceOver = (int) Math.round(finalPrice / 100d);
finalPrice = switch (finalPriceOver)
{
case 0,1 -> finalPrice;
case 2, 3, 4, 5, 6 -> finalPrice - (finalPrice / 100 * LOW_DISCOUNT);
default -> finalPrice - (finalPrice / 100 * STRONG_DISCOUNT);
};
yield finalPrice;
}
};
return invoicePrice;
}
Il codice che utilizza lo switch come expression è più compatto, leggibile e meno prono ad errori.