ScalaとJava:なぜScalaを学ぶ必要があるのですか?

公開: 2022-03-11

「Scalaは難しい」という声明には確かにいくつかの真実がありますが、学習曲線は投資する価値があります。 言語のより複雑な機能のいくつか(タプル、関数、マクロなど)は、最終的に、開発者がScalaでプログラミングすることにより、より優れたコードを記述し、パフォーマンスを向上させることを容易にします。 率直に言って、私たちはプログラマーであり、ある程度複雑な言語を学ぶのに十分賢くない場合、私たちは間違ったビジネスをしていることになります。

Scalaは、オブジェクト指向プログラミングと関数型プログラミングの両方を非常に簡潔で論理的で非常に強力な言語に組み込んだ、タイプセーフなJVM言語です。 Scalaが2003年に最初に導入されて、思ったほど新しくないことを知って驚く人もいるかもしれません。しかし、Scalaが重要な支持者を育て始めたのは、特に過去数年以内です。 「なぜScalaなのか」という疑問を投げかけるのはどれですか。

この記事では、特にJavaに対するScalaの利点を検証します(ScalaはJVMで実行するように作成されているため)。 「より良いJava」を作成する試みはScalaだけではありません。 KotlinやCeylonなどの代替手段もその道を進んでいますが、学習曲線を最小限に抑えるために、構文をJava言語自体に非常に近づけるという基本的な決定を下しました。 これは素晴らしいアイデアのように思えるかもしれませんが、そもそも「より良いJava」を作成したい理由であった、まったく同じJavaパラダイムの数にとどまることを余儀なくされるという点で、最終的にはやや自滅的です。

対照的に、Scalaは、より優れた言語になることを目的として特別に作成され、開発者にとって制限的、過度に退屈、または苛立たしいと見なされたJavaの側面を取り除きます。 その結果、Scalaプログラミングの早期学習を少し難しくする可能性のあるコードの区別とパラダイムシフトが実際にありますが、その結果、言語がはるかにクリーンで整理され、最終的には使いやすくなり、生産性が向上します。

ScalaとJavaを並べて比較すると、Scalaの効率は明らかです。

ScalaとJava:どちらが本当に複雑ですか?

皮肉なことに、Java言語の単純さはその成功の一部でしたが、その複雑さにも貢献しています。 もちろん、Javaでほとんど何でも書くことができますが、そうするために必要なコード行は気が遠くなる可能性があります。 一方、Scalaでのプログラミングは、少し複雑な構造になっています。 しかし、Javaの「より単純な」20行を置き換える、もう少し複雑な1行のコードを記述できるとしたら、どれが本当に複雑なのでしょうか。

真実は、Javaはしばしば冗長すぎるということです。 Scalaでは、コンパイラーは非常に賢いので、開発者がコンパイラーが推測できるものを明示的に指定する必要がなくなります。 たとえば、この単純な「HelloWorld!」を比較してください。 JavaとScalaのプログラム:

Hello World in Java:

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

スカラのHelloWorld:

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

ここでは2つの言語の間に大きな違いはありませんが、この単純な例でもScalaはそれほど冗長ではありません。

より実用的な例として、文字列の簡単なリストを作成してみましょう。

Java:

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

Scala:

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

確かに、Javaにはコードを少し短くするためのトリックがいくつかありますが、標準的な使用法ではありません。

ここで、数値である文字列のリストがあるが、そのリストを整数のリストに変換したい場合を考えてみましょう。

Java:

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

Scala:

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

Scalaの機能特性のおかげで、この変換は非常に簡単になります。

クラスの例:JavaとScala

さらに一歩進んで、JavaとScalaでの標準のBean /プレーンオールドJavaオブジェクト(POJO)の作成を比較してみましょう。

まず、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; } }

ふぅ。 ロッタコード。

今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 = _ }

どの言語がもっと複​​雑だと言いましたか?!

私たちは公平ですか?

ここまで進んでいて、Javaプログラマーであれば、この時点で、私がコードを不当に比較していると思っているかもしれません。 結局のところ、Javaでパブリック変数を作成し、ゲッターとセッターを取り除くことを妨げるものは何もありません。

ただし、Javaのゲッターとセッターの背後にある理由を振り返ると、これは特に将来を保証するためのものです。 つまり、後で変数の取得または設定にロジックを追加する必要がある場合は、代わりにメソッドを使用するようにそれらのパブリック変数を書き直す必要があります(そのため、Javaでは最初にゲッターとセッターを使用することをお勧めします)。 ただし、Scalaプログラミングでは、これは当てはまりません。 言語設計のため、抽象化はゲッターやセッターを必要とせずにそのまま残ります。 たとえば、名前をnullに設定しようとすると、 NullPointerExceptionをスローするScalaのこの変更されたUserクラスについて考えてみます。

 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 }

そして、あなたはまだこのように名前を設定することができます:

 user.name = "John Doe"

これにより、メソッドアクセサーを事前に構成する必要が完全になくなることに注意してください。

さらに、Scalaは不変性を好むので、これをScalaでケースクラスを使ってさらに簡潔に書くことができます。

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

私が書かなければならないコードがどれだけ少ないかはかなりクレイジーです。

例をもう少し取り上げます

ここで、 Userが注文したすべてのProductsのリストを返す、 Userクラスに気の利いた小さなメソッドを追加したい上記のクラスのシナリオを考えてみましょう。

Javaの冗長な世界では:

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

幸い、 java.util.ListにはaddAllメソッドがあります。そうでない場合、JavaではgetProducts()がさらに長くなります。

一方、Scalaでは、必要なのは次のことだけです。

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

Scala言語の実装がどれだけ小さいかがわかります。 はい、Scalaの初心者にはもっと複雑に見えるかもしれませんが、その背後にある概念を実際に完全に理解すると、ScalaコードはJavaコードよりもはるかに単純に見えます。

ここでもう少し複雑にしましょう。 特定のCategory内のProductsのみを取得したい場合はどうなりますか?

この場合、 java.util.ListaddAllメソッドを利用できないため、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; }

ただし、 Scalaでは、コードはかなり単純なままです。 flatMapを使用して、フラット化された各Orderの商品リストを1つのリストに結合し、次に、カテゴリに一致するもののみを含めるようにフィルタリングします。

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

動的vs静的

確かに過去数年間、新しい言語が不足することはありませんでしたが、最近登場した他のほとんどすべての言語は動的ですが、Scalaは静的に型付けされています。

私は多くの動的言語を知っており、使用していますが、プロの開発者として、コンパイル時のチェックは堅実なコードを書くために非常に重要であると私は考えています。 動的言語では、さまざまなシナリオで実際に実行するまで、コードに十分なバグがなく、堅牢であることを確認することはできません。 これにより、コードに重大な欠陥が生じる可能性があり、コードが本番環境に移行するまで実現されません。

要約

うまくいけば、この記事がJavaとScalaを十分に積み重ねて、Scalaのパワーと機能の予備的な感覚を与え、言語を学ぶ意欲を刺激することを願っています。 プログラミングを面倒で楽しくすることができる優れた言語であるだけでなく、世界最大の企業(LinkedIn、Twitter、FourSquare、The Guardianなど)でも使用されています。

Scala開発者の募集職種が増え続けていることからもわかるように、Scalaの人気と使用法は急速に増加しています。 まだ行っていない場合は、今が波に乗り始めて「なぜScalaを学ぶのか」と尋ねるのをやめる良い機会です。

関連: Scalaマクロと準引用符を使用してボイラープレートコードを削減する