当前位置:编程学习 > JAVA >>

Java.next: 下一代JVM语言

  在我与Martin Fowler曾经合作呈现的一次主题演讲中,他作出了一个有洞察性的观点:
    Java的遗产将是平台,而不是程序设计语言。
    Java技术的原始工程师们作出了一个明智的决定,就是将编程语言与运行时环境分开,最终这使得超过200种语言能够运行在Java平台上。这种架构对于该平台的长期活力是至关重要的,因为计算机程序设计语言的寿命一般都是比较短。从2008年开始,由Oracle主办的一年一度的JVM语言峰会为JVM上其它的语言实现与Java平台工程师进行开放式合作提供了机遇。
    欢迎来到Java.next专栏系列,在本系列的文章中,我将讲述三种现代JVM语言--Groovy,Scala和Clojure--它提供了范式,设计选择与舒适因子之间一种有趣的混合。在此我不会花时间去深入介绍每种语言;在它们各自的站点上都有这类深度介绍。但这些语言社区的站点--它们主要目的是为了传布这些语言--都缺乏客观的信息,或者是该语言不适用的例子。在本系列的文章中我将进行独立地比较,以填补上述空白。这些文章将概述Java.next程序设计语言,以及学习它们的好处。
 
超越Java
    Java程序设计语言达到卓越的程度就是,按Bruce Tate在他的Beyond Java一书中的说法,完美风暴:Web应用的兴起,已有Web技术由于种种原因不能适应需求,企业级多层应用开发的兴起,这些因素共同造就了Java的卓越。Tate也指出这场风暴是一系列独一无二的事件,曾经没有其它语言使用相同的途径达到相同的卓越程序。
    Java语言已经证明其在功能方面的强大灵活性,但它的语法与固有范式则存在着长期已知的局限性。尽管一些承诺过的变化即将引入到该语言中,但Java语法却不能很容易地支持一些重要的未来语法特性,例如函数式编程中的某些特性。但如果你试图去找到一种语言去替代Java,那么你就找错了。
 
多语言编程
    多语言编程--在2006年的一篇博客中我使这个术语重焕活力并重新流行起来--是基于这样的一种认识:没有一种编程语言能够解决每个问题。有些语言拥有某些内建的特性,使其能够更好地适应特定的问题。例如,由于Swing十分复杂,开发者们发现很难编写Java中的Swing UI,因为它要求事先声明类型,为UI动作定义烦人的匿名内部类,还有其它的麻烦事儿。使用更适合构建UI的语言,如Groovy中的SwingBuilder工具,去构建Swing应用会美妙得多。
    运行在JVM上的程序设计语言大量增多,这大大激发了多语言编程理念,因为你可以混用编号语言,并可使用最佳匹配的语言,但同时却维护着相同的底层字节码和类库。例如,SwingBuilder并不是要替代Swing;它只是搭建在已有的Swing API之上。当然,在相当长的时间内,开发者们还是将在JVM之外混合使用编程语言--例如,为特定目的而使用SQL和JavaScript--但在JVM的世界内,混合编程将变得更为流行。ThoughtWorks中的许多项目就合用着多种编程语言,而所有由ThoughtWorks Studios开发的工具则都要使用混合语言。
    即便Java仍是你主要的开发语言,学习一下其它语言是如何工作的会让你将它们纳入你的未来战略中。Java仍将是JVM生态系统中的重要组成部分,但最终它更多是作为该平台的汇编语言--或是由于纯粹的性能原因,或是在应对特殊需求时才会用到它。
 
编程语言的进化
    当上世纪八十年代我还在大学时,我们使用着一种称作Pecan Pascal的开发环境。它独一无二的特性就是能使相同的Pascal代码既可运行在Apple II上,又可以运行在IBM PC上。Pecan的工程师们为了实现这一目的使用了一种称作"字节码"的神秘之物。开发者们将他们的Pascal代码编译成"字节码",该"字节码"则运行在为各个平台编写的原生"虚拟机"上。那是一段可怕的经历!最终程序慢的出奇,即便只是一个简单的类赋值。当时的硬件无法应对这一挑战。
Pecan Pascal之后的十年,Sun发布了使用相同架构的Java,它受限也受利于上世纪九十年代的硬件环境。Java还加入了其它的对开发者友好的特性,如自动的垃圾收集。由于曾经使用过像C++之样的语言,现在我再也不想使用没有垃圾收集功能的语言去编码了。我宁愿花时间在更高抽象层次上去思考复杂的业务问题,而不是像内存管理这样的复杂管道问题。
    计算机语言通常没有很长寿命的原因之一就是语言和平台设计的创新速度。由于我们的平台变得更为强大,它们可以处理更多的额外工作。例如,Groovy的内存化(memoization)特性(2010年加入)会缓存函数调用的结果。不需要手工编写缓存代码,那样会引入潜在的缺陷,你仅仅只是需要调用memoize方法而以,如清单1所示:
清单1. 在Groovy中内存化函数
def static sum = { number ->
  factorsOf(number).inject(0, {i, j -> i + j})
}
def static sumOfFactors = sum.memoize()
 
    在清单1中,sumOfFactors方法返回的结果会被自动缓存。你还可以使用方法memoizeAtLeast()和memoizeAtMost()去定制缓存行为。Clojure也含有内存化特性,在Scala中也有略有实现。像内存化这样存在于下一代编程语言(以及某些Java框架)中的高级特性也将逐渐地进入到Java语言中。Java的下一个版本中将加入高阶函数(higher-order function),这使得内存化更容易被实现。通过研究下一代Java语言,你就可以先睹Java的未来特性为快了。
 
Groovy,Scala和Clojure
    Groovy是二十一世纪的Java语法--浓缩咖啡取代了传统咖啡。Groovy的设计目标是更新并消除Java语法中的障碍,同时还要支持Java语言中的主要编程范式。因此,Groovy要"知晓"诸如JavaBean,它会简化对属性的访问。Groovy会以很快的速度纳入新特性,包括函数式编程中的重要特性,这些特性我将在本系列的后续篇章中着重描述。Groovy仍然主要是面向对象的命令式语言。Groovy区别于Java的两个基本不同点:它是动态而非静态的;它是的元编程能力要好得多。
    Scala从骨子里就是为了利用JVM而进行设计的,但是它的语法则是完全被重新设计过了。Scala是强静态类型语言--它的类型要求比Java还严格,但造成的麻烦却很少--它支持面向对象和函数式范式,但更偏好于后者。例如,Scala更喜欢val声明,这会生成不可变变量(类似于在Java中将变量声明为final)赋给var,而var将创建更为大家所熟悉的可变变量。通过对这两种范式的深度支持,Scala为你可能想要的(面向对象的命令式编程)与你所应该想要的(函数式编程)之间架起了一座桥梁。
    Clojure是最激进的,它的语法是从其它语言中分离出来,被认为是Lisp的方言。Clojure是强动态类型语言(就像Groovy),它反映了一种义无反顾的设计决策。虽然Clojure允许你与遗留的Java程序进行全面而深度的交互,但是它并不试图构建一座桥梁去连接面向对象范式。例如,Clojure是函数式编程的铁杆,也支持面向对象以允许与该种范式进行互操作。尽管它支持面对对象程序员所习惯的全部特性,如多态--但,是以函数式风格,而非面向对象风格进行实现的。设计Clojure时遵循了一组核心的工程原则,如软件事务内存(Software Transactional Memory),这是为了迎合新功能而打破了旧有的编程范式。
 
编程范式
    除语法之外,这些语言之间的最有趣的不同之处就是类型及其内在的编程范式:函数式或命令式。
 
静态类型 vs. 动态类型
    编程语言中的静态类型要求显式的类型声明,例如Java中的int x;声明语句。动态类型语言并不要求在声明时提供类型信息。此处所考虑的语言都是强类型语言,意即程序在赋值之后能够反射出类型。
    Java的类型系统广受诟病之处就是其静态类型有太多不便,且又没有提供足够的益处。例如,在当前的有限的类型推导出现之前,Java要求开发者在赋值语句两边要重复地声明类型。Scala的类型比Java的更为静态,但在日常使用中所遇到的不便要少得多,因为它大量使用了类型推导。
    初看Groovy,它似乎有一种行为能够衔接静态与动态之间的隔阂。考虑如清单2所示的简单对象集合工厂:
清单2. Groovy集合工厂
class CollectionFactory {
  def List getCollection(description) {
    if (description == "Array-like")
      new ArrayList()
    else if (description == "Stack-like")
      new Stack()
  }
}
 
    清单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.MissingMeth
补充:软件开发 , Java ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,