Scala vs. Java: Por que devo aprender Scala?

Publicados: 2022-03-11

É certo que há alguma verdade na afirmação de que “Scala é difícil”, mas a curva de aprendizado vale o investimento. Alguns dos recursos mais complexos da linguagem (Tuplas, Funções, Macros, para citar alguns) tornam mais fácil para o desenvolvedor escrever código melhor e aumentar o desempenho programando em Scala. Francamente, somos programadores e, se não formos inteligentes o suficiente para aprender uma linguagem que tenha alguma complexidade, estamos no negócio errado.

Scala é uma linguagem JVM de tipo seguro que incorpora programação orientada a objetos e funcional em uma linguagem extremamente concisa, lógica e extraordinariamente poderosa. Alguns podem se surpreender ao saber que o Scala não é tão novo quanto eles pensavam, tendo sido introduzido pela primeira vez em 2003. No entanto, é particularmente nos últimos anos que o Scala começou a desenvolver um número significativo de seguidores. O que levanta a questão de “Por que Scala?”.

Este artigo examina as vantagens do Scala, especialmente em relação ao Java (já que o Scala foi escrito para ser executado na JVM). Scala não é a única tentativa de criar um “Java melhor”. Alternativas como Kotlin e Ceylon também seguiram esse caminho, mas tomaram a decisão fundamental de permanecer muito próximas em sintaxe da própria linguagem Java, de modo a minimizar a curva de aprendizado. Isso pode parecer uma ótima ideia, mas, em última análise, é um pouco autodestrutivo, pois força você a permanecer dentro de vários desses mesmos paradigmas Java que foram a razão para querer criar um “Java melhor” em primeiro lugar.

Em contraste, Scala foi criado especificamente com o objetivo de ser uma linguagem melhor, eliminando aqueles aspectos do Java que considerava restritivos, excessivamente tediosos ou frustrantes para o desenvolvedor. Como resultado, existem de fato distinções de código e mudanças de paradigma que podem tornar o aprendizado inicial da programação Scala um pouco mais difícil, mas o resultado é uma linguagem muito mais limpa e bem organizada que, em última análise, é mais fácil de usar e aumenta a produtividade.

Ao comparar Scala x Java lado a lado, a eficiência do Scala é clara.

Scala vs. Java: o que é realmente mais complexo?

Embora a simplicidade da linguagem Java tenha sido parte de seu sucesso, ironicamente, ela também contribuiu para sua complexidade. Claro, você pode escrever quase qualquer coisa em Java, mas as linhas de código necessárias para fazer isso podem ser assustadoras. A programação em Scala, por outro lado, tem uma estrutura um pouco mais complexa. Mas se você puder escrever uma única linha de código um pouco mais complexa que substitua 20 linhas “mais simples” de Java, qual delas é realmente mais complexa?

A verdade é que Java é muitas vezes muito verboso. Em Scala, o compilador é incrivelmente inteligente, então isso evita que o desenvolvedor precise especificar explicitamente as coisas que o compilador pode inferir. Compare, por exemplo, este simples “Hello World!” programa em Java vs. Scala:

Olá Mundo em Java:

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

Olá Mundo em Scala:

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

Embora não haja uma grande distinção entre as duas linguagens aqui, Scala é menos verboso mesmo neste exemplo simples.

Para um exemplo mais prático, vamos dar uma olhada na criação de uma lista simples de Strings:

Java:

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

Escala:

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

Certamente existem alguns truques em Java para encurtar um pouco o código, mas não no uso padrão.

Agora considere um caso em que temos uma lista de strings que são números, mas queremos converter essa lista em uma lista de inteiros:

Java:

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

Escala:

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

Graças às propriedades funcionais do Scala, esta conversão torna-se extremamente simples.

Um exemplo de classe: Java vs. Scala

Vamos dar um passo adiante e comparar a criação de bean padrão / objeto Java antigo simples (POJO) em Java e Scala.

Primeiro, a versão 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; } }

Ufa. Muito código.

Agora a versão 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 = _ }

Qual idioma dissemos que era mais complicado?!

Estamos sendo justos?

Se você chegou até aqui e é um programador Java, pode estar pensando neste momento que estou fazendo uma comparação injusta de código. Afinal, não há nada que me impeça de fazer variáveis ​​públicas em Java e depois me livrar dos getters e setters.

No entanto, se você pensar no raciocínio por trás de getters e setters em Java, é especificamente para prova de futuro. Ou seja, se mais tarde você precisar adicionar alguma lógica à obtenção ou configuração de variáveis, você terá que reescrever essas variáveis ​​públicas para usar métodos (e é por isso que o uso de getters e setters para começar é incentivado em Java ). No entanto, na programação Scala este não é o caso. Por causa do design da linguagem, a abstração permanece intacta sem a necessidade de getters e setters. Considere, por exemplo, esta classe User modificada em Scala que lança um NullPointerException se você tentar definir o nome como 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 você ainda pode definir o nome assim:

 user.name = "John Doe"

Observe que isso elimina totalmente a necessidade de pré-configurar os acessadores de método.

Além disso, como Scala prefere a imutabilidade, posso escrever isso em Scala de forma ainda mais concisa com classes case:

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

Muito louco quanto menos código eu tenho que escrever.

Levando o exemplo um pouco além

Agora considere um cenário com as classes acima onde eu quero adicionar um pequeno método bacana na classe User que retorna uma lista de todos os Products que o User encomendou:

No mundo detalhado de Java:

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

Felizmente, java.util.List tem um método addAll , ou getProducts() teria sido ainda mais longo em Java.

Em Scala, por outro lado, tudo o que precisamos é:

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

Você pode ver o quão menor é a implementação da linguagem Scala. Sim, pode parecer mais complexo para o novato em Scala, mas uma vez que você realmente entenda completamente os conceitos por trás dele, o código Scala parecerá muito mais simplista do que o código Java.

Vamos ficar um pouco mais complicados aqui. E se quisermos obter apenas os Products dentro de uma Category específica?

Nesse caso, não podemos tirar proveito do método addAll em java.util.List , então as coisas ficam mais feias em 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; }

Em Scala , no entanto, o código permanece bastante simples. Simplesmente usamos flatMap para combinar as listas de produtos de cada Order achatado em uma única lista, depois filtramos para incluir apenas os que correspondem à categoria:

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

Dinâmico vs. estático

Certamente não faltaram novas linguagens nos últimos anos, mas enquanto quase todas as outras que surgiram recentemente são dinâmicas, Scala é estaticamente tipada.

Como desenvolvedor profissional – embora eu conheça e use muitas linguagens dinâmicas – é minha opinião que as verificações em tempo de compilação são incrivelmente importantes para escrever um código sólido. Em uma linguagem dinâmica, você nunca pode ter certeza de que seu código está suficientemente livre de bugs e robusto até que você realmente o execute em uma ampla variedade de cenários. Isso pode levar a defeitos potencialmente graves no código que nunca são percebidos até que o código esteja em produção.

Embrulhar

Esperamos que este artigo combine Java vs. Scala o suficiente para lhe dar uma noção preliminar do poder e capacidades do Scala e aguçar seu apetite para aprender a linguagem. Não só é uma ótima linguagem que pode tornar a programação menos tediosa e mais agradável, mas também está sendo usada por algumas das maiores empresas do mundo (LinkedIn, Twitter, FourSquare, The Guardian, para citar apenas algumas).

A popularidade e o uso do Scala estão crescendo rapidamente, como evidenciado pelo número cada vez maior de posições abertas para desenvolvedores do Scala. Se você ainda não o fez, agora seria um bom momento para começar a surfar e parar de perguntar “Por que aprender Scala?”

Relacionado: Reduzir o código do Boilerplate com macros Scala e quase aspas