Java 编程语言诞生时所面临的限制与如今的开发人员所面临的条件有所不同。具体来讲,由于上世纪 90 年代中期的硬件的性能和内存限制,Java 语言中存在原语类型。从那时起,Java 语言不断在演化,通过自动装箱(autobox)消除了许多麻烦操作,而下一代语言(Groovy、Scala 和 Clojure)更进一步,消除了每种语言中的不一致性和冲突。 在这一期的文章中,我将展示下一代语言如何消除一些常见的 Java 限制,无论是语法上还是默认行为上。第一个限制是原语数据类型的存在。 原语的消亡 Java 语言最开始有 8 对原语和相应的类型包装器类(最初用于解决性能和内存限制),并通过自动装箱逐步地淡化了它们之间的区别。Java 下一代语言更进一步,让开发人员觉得好像根本不存在差别。 Groovy 完全隐藏了原语类型。例如,int 始终表示 Integer ,Groovy 自动处理数字类型的上变换,防止出现数值溢出错误。例如,请查看清单 1 中的 Groovy shell 交互: 清单 1. Groovy 对原语的自动处理
groovy:000> 1.class
===> class java.lang.Integer
groovy:000> 1e12.class
===> class java.math.BigDecimal
|
在 清单 1 中,Groovy shell 显示,即使是常量也是通过底层的类来表示的。因为所有数字(和其他伪装的原语)都是真正的类,所以可以使用元编程技术。这些技术包括将方法添加到数字中(这通常用于构建特定领域的语言,即 DSL),支持 3.cm 这样的表达式。在后面介绍可扩展性的那期文章中,我会更全面地介绍此功能。 与 Groovy 中一样,Clojure 自动屏蔽原语与包装器之间的区别,允许对所有类型执行方法调用,自动处理容量的类型转换。Clojure 封装了大量底层优化,这已在语言文档中详细说明(参阅 参考资料)。在许多情况下,可提供类型 hints,使编译器能够生成更快的代码。例如,无需使用 (defn sum[x] ... ) 定义方法,可以添加一个类型提示,比如 (defn sum[^float x] ... ) ,它会为临界区 (critical section) 生成更高效的代码。 Scala 也屏蔽了原语之间的区别,通常对代码的时效性部件使用底层原语。它还允许在常量上调用方法,就像 2.toString 中一样。借助其混搭原语和包装器的能力,比如 Integer ,Scala 比 Java 自动装箱更加透明。例如,Scala 中的 == 运算符可在原语和对象引用上正确运行(比较值,而不是引用),而不同于相同运算符的 Java 版本。Scala 还包含一个 eq 方法(以及一个对称的 ne 方法),它始终比较底层引用类型是否等效。基本而言,Scala 会智能地切换默认行为。在 Java 语言中,== 会对引用数据进行比较,您几乎不需要这么做,可以使用不太直观的 equals() 比较值。在 Scala 中,== 能正确运行(比较值),无论底层实现是什么,它还提供了一个方法来执行不太常见的引用相等性检查 (reference equality check)。 Scala 的这一特性表明,Java 下一代语言的一个重要优势在于:将低级细节卸载到语言和运行时,开发人员能够有更多的时间考虑更高级的问题。
简化默认行为 人们的看法高度一致,大部分 Java 开发人员都认为,在 Java 语言中常见的操作需要太多的语法。例如,属性定义和其他样板代码使类定义变得很杂乱,掩盖了重要的方法。所有 Java 下一代语言都提供了简化创建和访问过程的途径。 Scala 中的类和 case 类 Scala 已简化了类定义,可为您自动创建存取函数、赋值函数和构造函数。例如,请查看清单 2 中的 Java 类: 清单 2. Java 中简单的 Person 类
class Person {
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return name + " is " + age + " years old.";
}
}
|
清单 2 中惟一的非样板代码是改写的 toString() 方法。构造函数和所有方法都由 IDE 生成。相比快速生成代码,在以后轻松理解它更为重要。无用的语法增加了您在理解底层含义之前必须使用的代码量。 Scala Person 类 令人震惊的是,清单 3 中用 Scala 编写的简单 3 行定义就创建了一个等效的类:
|