Scala与Java(为什么要学习Scala())

本文概述

  • Scala与Java:哪个更复杂?
  • 一个类示例:Java vs. Scala
  • 我们公平吗?
  • 进一步举例说明
  • 动态与静态
  • 本文总结
诚然, ” Scala很难” 这一说法确实有些道理, 但是学习曲线很值得投资。该语言的某些更复杂的功能(例如, Tuples, Functions, Macros等)最终使开发人员可以更轻松地编写更好的代码并通过在Scala中进行编程来提高性能。坦白地说, 我们是程序员, 如果我们不够聪明, 无法学习某种复杂的语言, 那么我们就做错了事。
Scala是一种类型安全的JVM语言, 它将面向对象的程序和函数式编程都结合到一种极其简洁, 逻辑且功能强大的语言中。有些人可能会惊讶地发现Scala并不像他们想象的那么新, 它于2003年首次推出。但是, 尤其是在过去的几年中, Scala才开始获得大量关注。这就引出了” 为什么要使用Scala?” 的问题。
本文研究了Scala的优势, 尤其是与Java相比(因为Scala编写为在JVM中运行)。 Scala不是创建” 更好的Java” 的唯一尝试。诸如Kotlin和Ceylon之类的替代方案也走了这条路, 但他们做出了一个基本决定, 即在语法上保持与Java语言本身非常接近, 以最大程度地减少学习时间。这似乎是一个不错的主意, 但最终还是有些自欺欺人, 因为它迫使你停留在许多完全相同的Java范式中, 这些范式就是首先要创建” 更好的Java” 的原因。
相比之下, Scala的创建目的是成为一种更好的语言, 以摆脱Java认为对开发人员来说过于严格, 过于繁琐或令人沮丧的那些方面。结果, 确实存在代码差异和范式转换, 这可能会使Scala编程的早期学习变得更加困难, 但是结果是一种更加简洁和井井有条的语言, 最终更易于使用并提高了生产率。
Scala与Java(为什么要学习Scala())

文章图片
Scala与Java:哪个更复杂? 具有讽刺意味的是, 虽然Java语言的简单性是其成功的一部分, 但它也为其复杂性做出了贡献。当然, 你几乎可以用Java编写任何东西, 但是这样做所需的代码行可能令人生畏。另一方面, Scala中的编程结构稍微复杂一些。但是, 如果你可以编写稍微复杂一点的单行代码来代替Java的20条” 更简单” 的行, 那么哪一行真的更复杂?
事实是Java通常太冗长了。在Scala中, 编译器非常聪明, 因此避免了开发人员需要明确指定编译器可以推断的内容。比较一下这个简单的” Hello World!” Java vs. Scala中的程序:
Java中的Hello World:
public class HelloJava { public static void main(String[] args) { System.out.println("Hello World!"); } }

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

尽管此处的两种语言之间并没有很大的区别, 但即使在这个简单的示例中, Scala的详细程度也较低。
举一个更实际的例子, 让我们看一下创建一个简单的字符串列表:
Java:
List< String> list = new ArrayList< String> (); list.add("1"); list.add("2"); list.add("3");

规模:
val list = List("1", "2", "3")

当然, Java中有一些技巧可以缩短代码, 但在标准用法中却不行。
现在考虑一种情况, 我们有一个数字字符串列表, 但我们希望将该列表转换为整数列表:
Java:
List< Integer> ints = new ArrayList< Integer> (); for (String s : list) { ints.add(Integer.parseInt(s)); }

规模:
val ints = list.map(s => s.toInt)

借助Scala的功能特性, 这种转换变得非常简单。
一个类示例:Java vs. Scala 让我们更进一步, 比较Java和Scala中的标准Bean /普通旧Java对象(PO??JO)创建。
首先, 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; } }

ew Lotta代码。
现在是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创建公共变量, 然后摆脱getter和setter。
但是, 如果你回想一下Java中的getter和setter背后的原因, 那么它专门用于将来的验证。也就是说, 如果以后需要在获取或设置变量时添加一些逻辑, 则必须重新编写那些公共变量以使用方法(这就是Java中鼓励使用getter和setter开头的原因。 )。但是, 在Scala编程中并非如此。由于采用了语言设计, 因此抽象无需使用getter和setter即可保持完整。例如, 考虑一下Scala中经过修改的User类, 如果你尝试将名称设置为null, 则会抛出NullPointerException:
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与Java(为什么要学习Scala())】请注意, 这完全消除了预先配置方法访问器的需要。
而且, 由于Scala更喜欢不变性, 因此我可以使用case类更简洁地在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类中添加一个漂亮的小方法, 该方法返回用户订购的所有产品的列表:
在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代码看起来更加简单。
让我们变得更加复杂。如果我们只想获取特定类别中的产品怎么办?
在这种情况下, 我们无法利用java.util.List中的addAll方法, 因此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的产品列表合并到一个列表中, 然后进行过滤以仅包括与类别匹配的产品:
def productsByCategory(category: String) = orders.flatMap(o => o.products).filter(p => p.category == category)

动态与静态 在过去的几年中, 当然不缺少新语言, 但是尽管最近出现的几乎所有其他语言都是动态的, 但是Scala是静态类型的。
作为专业的开发人员(尽管我知道并使用许多动态语言), 我认为编译时检查对于编写可靠的代码非常重要。在动态语言中, 除非你在各种情况下实际运行它, 否则你将永远无法确保自己的代码没有足够的错误和健壮性。这可能导致代码中潜在的严重缺陷, 直到代码投入生产后才可能实现。
本文总结 希望本文将Java与Scala进行了充分的融合, 以使你对Scala的功能和能力有初步的了解, 并激发了你学习该语言的兴趣。它不仅是一种很棒的语言, 它可以使编程变得不那么乏味并且更加有趣, 而且还被世界上一些最大的公司(LinkedIn, Twitter, FourSquare, The Guardian等)使用。
Scala开发人员的空缺职位数量不断增加, 证明了Scala的受欢迎程度和使用量正在迅速上升。如果你还没有这样做的话, 那么现在将是一个开始尝试并停止询问” 为什么要学习Scala?” 的好时机。

    推荐阅读