英文原文:coderfriendly,编译:王晓杰
我希望你有机会看看这个视频“The future of the programming language”。这个会议是由C#的架构师Anders Hejlsberg 主导的,视频中他阐述了自己心目中的下一代编程语言应该具备的主要特性:
特定领域语言(Domain Specific Language, 简写DSL,包括内部及外部DSL)
有注解功能(将注意力集中在做什么而不是怎么做)
介于静态语言好动态语言之间的语言
面向过程语言(命令式语言(Imperative Language)并不适合面向多线程编程)
他的演讲非常棒,十分通俗易懂,从中我学到了很多,我相信微软拥有世界上最好的实验室。在演讲的最后,他说他不理解为什么Java还没有转向面向过程。作为一名Java开发者,我不得不承认.net平台确实非常强大。我喜欢他所倡导的”选一个自己喜欢的语言去编程吧!”
函数式编程
对于什么是函数式编程语言,Anders给出了一个很简要的描述。例如,在命令式语言中,会经常这么写:
x=x+1
我们已经按照这种方式编程很多年了,以至于我们几乎忘了其他的一些科学家们并不是这样做的。在数学领域,你应该这么写:
y=x+1
y的计算结果并不会改变x的值。这个例子可能有些过于简单,为了进一步说明,我们来假设有这样一个叫做”Number”的Java类。
- publicclassNumberImperative {
- privateint_value;
- publicNumberImperative(finalintvalue) {
- _value = value;
- }
- publicintgetValue(){
- return_value;
- }
- publicvoidadd(finalintnumberToAdd){
- _value += numberToAdd;
- }
- publicvoidsubstract(finalintnumberToSubstract){
- _value -= numberToSubstract;
- }
- }
以及第二种实现:
- publicclassNumberFunctional {
- privatefinalint_value;
- publicNumberFunctional(finalintvalue) {
- _value = value;
- }
- publicintgetValue(){
- return_value;
- }
- publicNumberFunctional add(finalintnumberToAdd){
- returnnewNumberFunctional(_value + numberToAdd);
- }
- publicNumberFunctional substract(finalintnumberToSubstract){
- returnnewNumberFunctional(_value - numberToSubstract);
我知道你可能喜欢写int y = x + 1;。但这个不是我们在这要讨论的。这两个例子中的代码给出了命令式语言和函数式语言的最基本用法,我们使用下面这个段代码来进行测试。
- publicfinalclassDemoNumber {
- publicstaticvoidmain(finalString[] args) {
- finalintx = 5;
- // imperative
- finalNumberImperative numberImperative = newNumberImperative(x);
- numberImperative.add(1);
- System.out.println("imperative: "+ numberImperative.getValue());
- // functional
- finalNumberFunctional numberFunctional = newNumberFunctional(x);
- finalNumberFunctional resultNumberFunctional = numberFunctional.add(1);
- System.out.println("functional: "+ resultNumberFunctional.getValue());
- }
- }
输出的结果为:
我都能够想象出你脸上的表情:”这哥们一定是个代码控,这么喜欢写代码”。别忘了,这只是一个例子,而且在现实生活中我们不需要写这样的类 (NumberFunctional)。但是,如果你习惯于开发线程安全的代码,那么你一定已经意识到函数式的实现方式是不可变类,而不可变类可以很容易 的解决并行执行过程中遇到的问题,JDK中有很多你可以随时初始化的不可变类,例如:String,Integer,Double等。
在未来几年,随着多核微处理的普及,并行编程将成为开发人员必须要具备的核心竞争力。在NumberImperative类中,因为成员变量 “_value”是没有同步的,所以在运行时将产生副作用。即便是我们对这个属性进行了同步,但如果拥有同一个引用的两个线程同时调用下面的函数的话,仍旧会形成竞争条件:
- publicvoidatomicProblem(finalNumberImperative numberImperative){
- if(numberImperative.getValue() == 0){
- numberImperative.add(1);
如果你读过Brian Goetz的书“Java Concurrent in practice“,你可能会想到在你的代码中加入Annotation。我们可以将NumberImperative类注解成 @NotThreadSafe,而将NumberFunctional类注解成@Immutable。
函数式语言默认就是不可更改的。如果我们想让一个数据变得可以更改,我们需要追加一个关键字,比如: Closures,你可以参照Refs and Transactions。在F#语言中可以使用 mutable关键字,而在Scala中,可以用“var” 和 “val”这两个关键字。
大势所趋
目前我们所遇到的问题是,由于JCIP Annotation还不够普及,构建一个线程安全的软件是十分困难的。就连一些Java标准类也没有加入Annotation,如果你的团队中的某些人没有看过 Brian Goetz的书, 那么他/她很可能不知道如何编写线程安全的类,如何使用Annotation。在我的团队中,我总是认为那些没有JCIP Annotation的类不是线程安全的。但是就连鼎鼎大名的Findbugs ,也无法帮你找出那些没有加入Annotation的类。因此,要查找并发Bug是十分困难的。
那么,如何迫使程序员去适应并发编程呢?我想我们不能要求所有的程序员去检查他的程序是否存在并发的问题。我遇到过很多不喜欢读书的程序员,因此JCIP相关的书籍也不是一个好的解决方案。Java是 James Gosling在 1995年创造的,那已经是14年前的事情了。现在我们发现要创建一个用Java写的并发软件的唯一方法就是,强化注解,并且对代码用工具进行静态分析。 但是你我都只知道,工具并不能使问题编程更简单,只是让他变得能够管理。依我看来,想要迫使人们去学习新的方法论,一门新的语言是唯一的选择。这样程序员 就必须去学习新的内容,去改变他们原有的习惯.
放弃Java?
就目前来看,答案当然是否定的。Java非常的普及,庞大的社区需要很长时间才会接受新的编程语言.我想新的语言应该是面向少数先知先觉者的,并且需要经过多年的历练才会崛起。一篇文章中这么写道:最近确实有很多关于Java语言未来的博客,Daniel Weinreb强调“Java的普及率太高了,我们不太可能看到它消失”。同时,James Iry的观点是“他目前是并且在未来很长一段时间内,都将是IT经理为数不多的几个最安全的选择其中之一”。
因此,作为一个Java开发人员,我们需要竖起耳朵去聆听市场的声音,并且不断地提高自己以便适应未来五年内可能发生的迁移。目前我们还是要现在工具编写并发程序,因此我们需要继续读 Brian Goetz的书。并且在多线程场景中提高警惕。
那么你呢,你会给Java开发人员哪些建议?