Scala vs Java: perché dovrei imparare Scala?

Pubblicato: 2022-03-11

C'è certamente del vero nell'affermazione che "Scala è difficile", ma la curva di apprendimento vale l'investimento. Alcune delle caratteristiche più complesse del linguaggio (Tuple, Funzioni, Macro, solo per citarne alcune) rendono più facile per lo sviluppatore scrivere codice migliore e aumentare le prestazioni programmando in Scala. Francamente, siamo programmatori e se non siamo abbastanza intelligenti da imparare un linguaggio che ha una certa complessità, allora siamo nel business sbagliato.

Scala è un linguaggio JVM type-safe che incorpora sia la programmazione orientata agli oggetti che quella funzionale in un linguaggio estremamente conciso, logico e straordinariamente potente. Alcuni potrebbero essere sorpresi di sapere che Scala non è così nuovo come pensavano, essendo stato introdotto per la prima volta nel 2003. Tuttavia, è soprattutto negli ultimi anni che Scala ha iniziato a sviluppare un seguito significativo. Il che pone la domanda “Perché Scala?”.

Questo articolo esamina i vantaggi di Scala, in particolare rispetto a Java (poiché Scala è scritto per essere eseguito nella JVM). Scala non è l'unico tentativo di creare un "Java migliore". Anche alternative come Kotlin e Ceylon hanno seguito quella strada, ma hanno preso la decisione fondamentale di rimanere molto vicine nella sintassi al linguaggio Java stesso, in modo da ridurre al minimo la curva di apprendimento. Può sembrare un'ottima idea, ma alla fine è in qualche modo controproducente in quanto ti costringe a rimanere all'interno di un certo numero di quegli stessi paradigmi Java che erano la ragione per voler creare un "Java migliore" in primo luogo.

Al contrario, Scala è stato creato specificamente con l'obiettivo di essere un linguaggio migliore, eliminando quegli aspetti di Java che considerava restrittivi, eccessivamente noiosi o frustranti per lo sviluppatore. Di conseguenza, ci sono davvero distinzioni di codice e cambiamenti di paradigma che possono rendere un po' più difficile l'apprendimento precoce della programmazione Scala, ma il risultato è un linguaggio molto più pulito e ben organizzato che in definitiva è più facile da usare e aumenta la produttività.

Confrontando Scala e Java fianco a fianco, l'efficienza di Scala è chiara.

Scala vs Java: qual è davvero più complesso?

Mentre la semplicità del linguaggio Java è stata parte del suo successo, ironia della sorte, ha anche contribuito alla sua complessità. Certo, puoi scrivere quasi tutto in Java, ma le righe di codice richieste per farlo possono essere scoraggianti. La programmazione in Scala, invece, ha una struttura leggermente più complessa. Ma se puoi scrivere una singola riga di codice leggermente più complessa che sostituisce 20 righe "più semplici" di Java, quale è davvero più complessa?

La verità è che Java è spesso troppo prolisso. In Scala, il compilatore è incredibilmente intelligente, quindi questo evita che lo sviluppatore debba specificare esplicitamente quelle cose che il compilatore può dedurre. Confronta, ad esempio, questo semplice "Hello World!" programma in Java vs Scala:

Ciao mondo in Java:

 public class HelloJava { public static void main(String[] args) { System.out.println("Hello World!"); } }

Ciao Mondo in Scala:

 object HelloScala { def main(args: Array[String]): Unit = { println("Hello World!") } }

Anche se qui non c'è un'enorme distinzione tra le due lingue, Scala è meno prolisso anche in questo semplice esempio.

Per un esempio più pratico, diamo un'occhiata alla creazione di un semplice elenco di stringhe:

Giava:

 List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); list.add("3");

Scala:

 val list = List("1", "2", "3")

Certamente ci sono alcuni trucchi in Java per accorciare un po' il codice, ma non nell'uso standard.

Consideriamo ora un caso in cui abbiamo un elenco di stringhe che sono numeri, ma vogliamo convertire quell'elenco in un elenco di numeri interi:

Giava:

 List<Integer> ints = new ArrayList<Integer>(); for (String s : list) { ints.add(Integer.parseInt(s)); }

Scala:

 val ints = list.map(s => s.toInt)

Grazie alle proprietà funzionali di Scala, questa conversione diventa estremamente semplice.

Un esempio di classe: Java vs Scala

Facciamo un ulteriore passo avanti e confrontiamo la creazione di bean standard / plain old Java object (POJO) in Java e Scala.

Innanzitutto, la versione Java:

 public class User { private String name; private List<Order> orders; public User() { orders = new ArrayList<Order>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Order> getOrders() { return orders; } public void setOrders(List<Order> orders) { this.orders = orders; } } public class Order { private int id; private List<Product> products; public Order() { products = new ArrayList<Product>(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public List<Product> getProducts() { return products; } public void setProducts(List<Product> products) { this.products = products; } } public class Product { private int id; private String category; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } }

Uff. Codice Lotta.

Ora la versione Scala:

 class User { var name: String = _ var orders: List[Order] = Nil } class Order { var id: Int = _ var products: List[Product] = Nil } class Product { var id: Int = _ var category: String = _ }

Quale lingua abbiamo detto che era più complicata?!

Siamo onesti?

Se sei arrivato così lontano e sei un programmatore Java, a questo punto potresti pensare che sto facendo un confronto ingiusto del codice. Dopotutto, non c'è nulla che mi impedisca di creare variabili pubbliche in Java e quindi di sbarazzarmi di getter e setter.

Tuttavia, se ripensi al ragionamento dietro getter e setter in Java, è specificamente per la prova del futuro. Cioè, se in seguito è necessario aggiungere un po' di logica all'ottenimento o all'impostazione delle variabili, è necessario riscrivere quelle variabili pubbliche per utilizzare invece i metodi (motivo per cui l'uso di getter e setter per cominciare è incoraggiato in Java ). Tuttavia, nella programmazione Scala questo non è il caso. A causa del design del linguaggio, l'astrazione rimane intatta senza bisogno di getter e setter. Si consideri, ad esempio, questa classe User modificata in Scala che genera una NullPointerException se si tenta di impostare il nome su null:

 class User { private var _name: String = _ var orders: List[Order] = Nil def name = _name def name_=(name: String) = { if (name == null) { throw new NullPointerException("User.name cannot be null!") } _name = name }

E puoi ancora impostare il nome in questo modo:

 user.name = "John Doe"

Si noti che questo elimina completamente la necessità di preconfigurare le funzioni di accesso del metodo.

Inoltre, poiché Scala preferisce l'immutabilità, posso scriverlo in Scala in modo ancora più conciso con le classi case:

 case class User(name: String, orders: List[Order]) case class Order(id: Int, products: List[Product]) case class Product(id: Int, category: String)

Abbastanza pazzesco quanto meno codice devo scrivere.

Prendendo l'esempio un po' più lontano

Consideriamo ora uno scenario con le classi precedenti in cui voglio aggiungere un piccolo metodo ingegnoso nella classe User che restituisce un elenco di tutti i Products ordinati User :

Nel verboso mondo di Java:

 public List<Product> getProducts() { List<Product> products = new ArrayList<Product>(); for (Order order : orders) { products.addAll(order.getProducts()); } return products; }

Fortunatamente, java.util.List ha un metodo addAll , o getProducts() sarebbe stato ancora più lungo in Java.

In Scala, invece, ci basta:

 def products = orders.flatMap(o => o.products)

Puoi vedere quanto è piccola l'implementazione del linguaggio Scala. Sì, può sembrare più complesso per il principiante di Scala, ma una volta che avrai compreso appieno i concetti alla base, il codice Scala apparirà molto più semplicistico del codice Java.

Diventiamo ancora un po' più complicati qui. E se volessimo ottenere solo i Products all'interno di una specifica Category ?

In questo caso non siamo in grado di sfruttare il metodo addAll in java.util.List , quindi le cose diventano più brutte in Java :

 public List<Product> getProductsByCategory(String category) { List<Product> products = new ArrayList<Product>(); for (Order order : orders) { for (Product product : order.getProducts()) { if (category.equals(product.getCategory())) { products.add(product); } } } return products; }

In Scala , tuttavia, il codice rimane abbastanza semplice. Utilizziamo semplicemente flatMap per combinare gli elenchi di prodotti di ciascun Order appiattito in un unico elenco, quindi filtriamo per includere solo quelli che corrispondono alla categoria:

 def productsByCategory(category: String) = orders.flatMap(o => o.products).filter(p => p.category == category)

Dinamico vs statico

Non sono certo mancate le nuove lingue negli ultimi anni, ma mentre quasi tutte le altre emerse di recente sono dinamiche, Scala è tipizzata staticamente.

Come sviluppatore professionista, sebbene io conosca e utilizzi molti linguaggi dinamici, è mia opinione che i controlli in fase di compilazione siano incredibilmente importanti per scrivere codice solido. In un linguaggio dinamico, non puoi mai essere sicuro che il tuo codice sia sufficientemente privo di bug e robusto finché non lo esegui effettivamente in un'ampia gamma di scenari. Ciò può portare a difetti potenzialmente gravi nel codice che non vengono mai realizzati fino a quando il codice non è in produzione.

Incartare

Si spera che questo articolo combini abbastanza Java rispetto a Scala per darti un'idea preliminare della potenza e delle capacità di Scala e stuzzicare il tuo appetito per l'apprendimento della lingua. Non solo è un ottimo linguaggio che può rendere la programmazione meno noiosa e più divertente, ma è anche utilizzato da alcune delle più grandi aziende del mondo (LinkedIn, Twitter, FourSquare, The Guardian, solo per citarne alcune).

La popolarità e l'utilizzo di Scala sono in rapido aumento, come dimostra il numero sempre crescente di posizioni aperte per gli sviluppatori di Scala. Se non l'hai già fatto, ora sarebbe un buon momento per iniziare a cavalcare l'onda e smettere di chiedere "Perché imparare Scala?"

Correlati: Riduci il codice Boilerplate con Macro Scala e Quasiquotes