Java.next: 下一代JVM语言

欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入

  清单2中的类表现为一个工厂类,基于传入的description参数,该工厂返回List接口的两种实现–ArrayList或Stack–之一。对于Java开发者,上述代码确保了返回值能够符合约定。然后,清单3中的两个单元测试揭示了一种复杂性:

  清单3. Groovy中的集合类型测试

  @Test

  void test_search() {

  List l = f.getCollection(“Stack-like”)

  assertTrue l instanceof java.util.Stack

  l.push(“foo”)

  assertThat l.size(), is(1)

  def r = l.search(“foo”)

  }

  @Test(expected=groovy.lang.MissingMethodException.class)

  void verify_that_typing_does_not_help() {

  List l = f.getCollection(“Array-like”)

  assertTrue l instanceof java.util.ArrayList

  l.add(“foo”)

  assertThat l.size(), is(1)

  def r = l.search(“foo”)

  }

  在清单3中的第一个单元测试中,使用前述的工厂类获得一个Stack对象,并验证它是否确实是Stack对象,然后再执行栈操作,例如push(),size()和search()。然而,在第二个单元测试中,我必须声明一个期望的异常MissingMethodException才能确保该测试能够通过。当我获取一个Array-like的集合,并将它赋给List类型的变量时,我能够验证返回的类型确为一个List对象。但是,当我试图调用search()方法时将触发异常,因为ArrayList并不包含search()方法。因此,这种声明无法在编译时确保方法的调用是正确的。

  虽然这看起来像是一个缺陷,但这种行为却是恰当的。Groovy中的类型只是确保赋值语句的有效性。例如,在清单3中,如果返回的实例未实现List接口,将会触发一个运行时异常GroovyCastException。鉴于此,可以肯定Groovy能够与Clojure同跻身于强动态类型语言家族。

  然而,Groovy最新的一些变化使得它的静态与动态之间的隔阂变得扫地清。Groovy 2.0加入了注解@TypeChecked,该注解可使你特别地对类或方法决定进行严格的类型检查。清单4例证该注解的使用:

  清单4. 使用注解的类型检查

  @TypeChecked

  @Test void type_checking() {

  def f = new CollectionFactory()

  List l = f.getCollection(“Stack-like”)

  l.add(“foo”)

  def r = l.pop()

  assertEquals r, “foo”

  }

  在清单4中,我加入了注解@TypeChecked,它同时对赋值及随后的方法调用进行了验证。例如,清单5中的代码将不能通过编译:

  清单5. 防止无效方法调用的类型检查

  @TypeChecked

  @Test void invalid_type() {

  def f = new CollectionFactory()

  Stack s = (Stack) f.getCollection(“Stack-like”)

  s.add(“foo”)

  def result = s.search(“foo”)

  }

  在清单5中,我必须对集合工厂返回的对象进行强制类型转换,这样才能允许我调用Stack类中的search()方法。但这种方式会产生一些局限性:当使类型静态化之后,Groovy的很多动态特性将无法工作。然而,上述救命证明了Groovy将继续进行改进,以弥合静态性与动态性之间的分歧。

  所有这些语言都有十分强大的元编程功能,所以更为严苛的类型化可以在事后再添加进来。例如,已有多个分支项目将选择性类型(selective type)引入到Clojure中。但一般认为选择性类型是可选的,它不是类型系统的一部分;它只是一个类型验证系统。

  命令式 vs. 函数式

  另一个主要的比较维度就是命令式与函数式。命令式编程注重于单步执行的结构,在许多情况下,它是模仿了早期底层硬件的有益结构。函数式编程则注重将函数作为第一等的结构体,以试图将状态传递与可变性降低到最小。

  Groovy在很大程度上是受Java的启发,它在根本上仍然是命令式语言。但从一开始,Groovy就加入了许多函数式命令的特性,并且以后还会加入更多的此类特性。

  Scala则弥合了这两种编程范式,它同时支持这两种范式。在更偏向(也更鼓励)函数式编程的同时,Scala依然支持面向对象和命令式编程。因此,为了恰当地使用Scala,就要求团队要受到良好的培训,以确保你不会混用和随意地选择编程范式,在多范式编程语言中,这一直都是一个危险。

  Clojure是铁杆的函数式编程语言。它也支持面向对象特性,使得它能够很容易地与其它JVM语言进行交互,它并不试图去弥合这两种范式之间的隔阂。相反,Clojure这种义无反顾的决策使它的设计者所考虑的语句成为很好的工程学实践。这些决策具有深远的影响,它使Clojure能够以开创性的方法去解决Java世界中一些挥之不去的问题(如并发)。

  在学习这些新语言时所要求的许多思想上的转变就是源自于命令式与函数式之间的巨大差别,而这也正是本系列文章所要探索的最有价值的领域之一。

[1][2]

那么,不如我们礼貌地保持相对距离,不至于太冷,不至于太痛。

Java.next: 下一代JVM语言

相关文章:

你感兴趣的文章:

标签云: