代码改变世界

事理越辩越明,那么就来详细说说为什么我不喜欢Java*语言*

2009-04-19 02:56 Jeffrey Zhao 阅读(...) 评论(...) 编辑 收藏

写在前面:这篇文章是在谈Java“语言”,文章里面也会再强调一下的。支持.NET的朋友也不用认为Java平台就此没落了,搞Java也没必要用Java平台的其他优势来反驳。咱吵架也要专业点,不是么。

最近我对Java语言唱衰似乎凶狠了一点,让有些朋友不是很爽,认为我不负责任凭个人感觉乱说话,影响不好。这讨论事情事小,否认我做事方式就不好了。因此我这里也继续整理一下我对Java语言的观点,这样大家不必四处查看我的说辞,再者也可以控制一下讨论事情的方式,以免大家舞蹈半天尘土飞扬最后停下一看——得,双方在自说自话,这怎能辩明事理,您说呢?

在这里,我借用一下郑晖同学(再此强烈推荐一下他的《冒号课堂》系列,如此好文不该受到如此冷落)在《高阶函数、委托与匿名方法》中留下的评论,这可能也是目前为止最具体最集中的质疑了。我很喜欢,因为可以一条一条的应对,思路清晰。

质疑:Java固步自封?Java语言从1.0到即将的7.0,每次都有新的语法特征加入。C#作为后辈,起点高,对函数式、动态类型等的支持是Java所没有的,但不代表Java今后就不支持。

回应:首先,“Java语言从1.0到7.0,每次都有新语法加入”,就能代表它“不固步自封”了吗?固步自封,是说它改进不大,不顺应“历史潮流”。C#的很多特性Java没有,但不代表Java今后不支持——是啊,的确“能力”是肯定有的,但是有能力而不去做,难道这不是“固步自封”的最好证明?Java 7已经再一次把业界早已强烈要求的闭包特性排除在门外了,只是增加了一些例如“[]式下标”或“使用->而不是get/set访问属性”这样的简单语法糖,看看每次C#改进的力度,具有可比性吗?

质疑:此外,Java的小兄弟Groovy也是动态语言,与Java很容易集成。其他的如JRuby、Jython与Java的集成也不难。

回应:JVM上实现的Groovy、Ruby、Python语言实现,不是我想讨论的内容。我说的是Java语言,由语言的规约来确定。我说Java生产力低下,其实只是说Java这门语言在设计上特性缺失过于严重,而不评论所谓JVM的能力。而JVM上可以实现Groovy等高生产力语言,更是证明了JVM的能力是完全足够的,而Java有那么好的平台基础,却不愿意发展,这也是我说的“固步自封”的原因之一。

质疑:要知道,Java有更多的历史包袱,动辄在语法上作大改动,会牵连到大批用户。这是成熟和流行的代价。

回应:我想说的是,“改进语言”并不代表如Rails 2之于Rails 1.2,Python 3之于Python 2.5那样的“破坏性”改变。改进语言只要保持向前兼容,还会有什么问题吗?难道C#1.0到3.0的过程中破坏了以前的程序吗?很明显,C# 1.0中的所有语法到3.0还可以用,而.NET Fx 1.0编写出的应用程序在3.5上也基本能用。这不就是很好的证明吗?这样的升级无论是语言(包括语法和IL/Binary Code级别的指令)、框架/类库、亦或是平台都不会造成问题,为什么在Java上面就成为无法升级的理由了呢?Java为.NET证明了统一托管平台的成功,由此诞生了.NET,而.NET为Java证明了那么多有生产力的高级语法,社区也吵吵嚷嚷多年——Java又在做什么呢?

质疑:想想c++吧,十年还没有出一个新标准呢。另外,微软一直不肯提供C#在Windows平台之外的支持,算不算固步自封呢?

回应:最后说C++,十年还没有出一个新标准——我不知道,我不关心别人为什么做的不好,我不关心别人的缺点为什么就能成为我不向前看的理由。我不提C++的另一个原因,是因为我对它的了解程度还不够,说了怕别人笑话。还有说微软一直不让C#在Windows以外平台上支持,这是固步自封吗?这是微软的一贯策略而已,当然这个策略我也不会认为是好事,但是谁能告诉我为什么这就叫“固步自封”?难道没有看到mono已经越来越引人注目了吗?微软在这方面的确“封闭”,但可没有“固步自封”。

质疑:Java开发效率虽然比Ruby、Python低,但有丰富的类库、框架和开发工具,更何况Java语言更加严谨,程序员的风格较为一致,减少了许多可能的犯错机会。综合起来,其效率真的会比C#低吗?

回应:某个语言“功能强大”,便说它“混乱”,自己“能力不足”便说是“严谨”。说实话,我认为这是一个很可笑的理由——不过也不是第一次见到这样的说法。从Ruby流行开始就有这种说法了,每次我都看得无可奈何,一笑了之。记得之前哪位朋友在园子里说过类似的话:“人们都希望事物发展,但是一旦事物发展让自己感到难以控制,就会引起恐慌,并对其打压”。虽然当时是在说C#语法的升级,但是现在也恰好可以用在C#与Java方面。至于框架的强大——我知道这一点肯定会被拿出来提,因此每次说Java“坏话”时总归会强调一下Java这一优势,只可惜似乎又被忽略了。那么我再强调一次,我谈论的是Java语法的生产力,不是Java平台的生产力——平台上框架的强大,难道语言上就可以不进行改进了吗?难道进行了语言能力上的强化,用它编写的框架就会变少了吗?平台能力就减弱了吗?当一个事物要用其优势来为自己的劣势做掩饰的时候……我就不多说了。

质疑:“难以辩驳的事实”是从什么数据得来的?太夸张了吧?即使用C和C++,只要对语言足够的熟悉,也不致于寸步难行。若果真Java如此难用,Java早就被淘汰了,不劳你唱衰了。

回应:我错了,我举不出“数据”,但是以前的文章都已经给过“示例”,个中比较可以由大家自行体会。至于“寸步难行”……的确也是我夸张了,我错了,以后不随意用修辞手法了。至于Java是否难用,是否早该被淘汰,我想说的是,您又犯了“极端化”的逻辑滑坡错误了。Java的确难用,但是我并没有说他难用到以至于无法推广,无法使用的地步。Java也不是没有过“优雅”的时期,只是到现在来说已经太不够看了,而且还是那四个字“固步自封”。我也从来没说Java平台应该被淘汰了,我还眼馋它们上面那么多项目呢,而且平台的能力并不是一个“语法”一个因素就能“拖垮”的。那么多年下来,大家早有依赖性了,肯定会继续用Java。不过我想说,如果回到十几年前Java刚出现那会儿,出现一种各方面都和Java一样,唯一的区别便是拥有C#语法的语言,Java能否活到现在还是个问题。

质疑:“你可以说ruby某个功能1行就能做,而C#要5行,那么我可以补充一个类库,完成1 行的功能。而Java就做不到”为什么Java就做不到呢?能说个理由吗?“这也是为什么现在不少编程语言的书,都喜欢和Java做对比,因为Java的生产力的确是‘难以提高’”——这个说法十分站不住脚。什么语言都与Java比,那是因为Java是当今最流行的语言。等C#在流行度超过了Java,人们自然会找C#比。

回应:不知道郑同学说这句话的时候有没有看过我那篇文章中给出的链接——没看过也不要紧,现在我再整理一下。那篇文章是《从CSDN的趣味题学C# 3.0》,因为有朋友认为Python做字符串小游戏很顺手,于是我也就顺便使用C#实现了一下,体现以下C# 3.0的强大特性。这个字符串游戏挺有意思的,不如郑同学用Java也来玩一下?C# 3.0已经不同以往,引入了Lambda表达式、扩展方法、LINQ语法之后在很多方便已经不熟于Ruby、Python等语言,用来玩玩这种小游戏也丝毫不落下风。而且您还别认为这只是一个“玩具”,就在我《高阶函数、委托与匿名方法》这篇文章里就用Java来设法“模拟”了一把C#里轻易实现的功能,不知道郑同学对此如何感想——求求您不要告诉我这个例子实际生产中没有用,因为这并不是我乱想出来的,在函数式编程语言,或者Parallel Fx中早就大量运用了。我懒得“列举”出来了,原谅我吧。

至于“作对比”是因为“流行”还是“能力”原因,似乎有点微妙,在这里不多作讨论了。现在呢我想多谈谈为什么说“生产力的确是难以提高”——我忽然又想到当时初学Ruby时看的《Everyday Scripting with Ruby》一书中对Ruby的功能大家赞赏,尤其是它的正则表达式配合灵活强大的语法给我留下了无比深刻的印象。当时C#还处于2.0阶段,由于没有Lambda表达式和扩展方法的特性,C#在这方面远远落后于Ruby。不过不久之前刚好施杨同学刚好需要《实现一个项目需求》,要求把一个字符串中1存在的位置区间表现出来,例如“00101111110111101110 => 3, 5-10, 12-15, 17-19”,这时某位匿名大虾用Ruby给出了一段实现,很好很强大:

i=0;
"00101111110111101110"
    .scan(/0+|1+/)
    .map
    {|s|
        l=s.length;
        i+=l;
        s.to_i.zero? ? nil : (l>1 ? "#{i-l}-#{i-1}" : "#{i-l}")
    }.compact * ", "

虽然在正则表达式的使用上略有缺陷,不过这段代码使用表达式配合map方法把Ruby的特点实实在在地表现了出来,很有典型意义。我一时兴起,也用C#实现了一把类似的:

String.Join(
    ", ",
    Regex.Matches("00101111110111101110", "1+")
        .Cast<Match>()
        .Select(m =>
            m.Length == 1 ?
                m.Index + 1 + "" :
                String.Format("{0} - {1}", m.Index + 1, m.Index + m.Length))
        .ToArray())

嗯嗯,更好地利用了类库中正则表达式的功能,因此整体上更“函数式”一些,也更流畅了一些,不过基本思路是和之前的Ruby实现是一样的。不过好像……还是不够意思?没事,咱可以扩展嘛,简单扩展以后就可以变成这样了:

"00101111110111101110"
    .Scan("1+")
    .Select(
        m => m.Length == 1 ?
            m.Index + 1 + "" :
            String.Format("{0} - {1}", m.Index + 1, m.Index + m.Length))
    .Join(", ");

简简单单扩展10行代码,这边的实现便可以更进一步,这便是语言的能力,C#能做到,Ruby能做到,而我的Java造诣只能得出“Java无法实现”的结论了,又不知哪位兄台可以试试看?由于语言能力的缺乏,“无法提高”也已经是“不争的事实”了,还需要更多证据吗?其实我最近也常思考一个问题,那就是“语言和框架/类库”之间的关系以及重要性。目前我的结论是:语言与框架/类库相辅相成,但总体来说“语言 > 框架/类库”,因为框架类库可以在现有语言能力的基础上进行补充,新开发也好,从其他平台进行移植也好,都很难说是“能力”问题。但是语言难以由框架来增强,框架最多只能为“特定场景”增强,无法弥补“语言”上的整体能力缺失。关于这个问题,也欢迎大家和我一起来讨论。

质疑:楼主喜欢C#是你的事情,犯不着一而再、再而三地贬低Java吧?没有人反驳你,是因为园子里大多以.net技术为主,对Java不一定熟悉,而你在这里似乎又是个权威。但那不代表你说的都是正确的。本来你关起门来自说自话,我也不会费神去反驳。但既然放在首页,总要经得起推敲吧?尤其你还是个在园子里有影响的人,说话更要严谨。楼主听惯了太多的恭维话,我的话想必有些刺耳。先别急着反驳我,心平气和地想一想。一个好的程序员,应该有一颗开放的心,任何语言、任何技术都可为我所用,不带偏见,不拘一格。

回应:这可真是“终极质疑”了,直接怀疑我的做事方式,我不爱听,必须好好解释一下。我贬低Java不是因为偏见,而是因为Java本身不争气;我也在很多公开场合(比如.NET技术大会或MSDN Web Cast的讲座时,还够正式吧)发表对微软的不满(比如Oxite这个绝佳的反面教材);此外,博客园给我带来那么多好处,我不也很有唱衰的欲望吗?——这是一贯做事方式而已,不搞“平衡”,一个东西某方面不好也不会非要帮它找理由来掩盖。当然我承认,里面可能会夹杂对C#的好感,但是至少我举出自认为非常恰当的实例来证明我的观点。我也知道弟兄们对我的厚爱,因此说话最多“偷懒”不会“随意”,说出来的话自认非常严谨,欢迎大家推敲,也欢迎郑同学在此继续推推敲敲——不过咱讨论问题不光要“讲道理”,还要“摆事实”不是吗?郑同学的质疑啥都好,条理清晰,就是缺少事实依据。对您这点要求不为过吧?这也不光是对您的要求,我现在这篇文章也够有诚意了是不?

我其实也做过1年多2年不到的Java程序员,也一直在关注Java(语言和框架)的发展,做出现在这样的判断绝不是图一时之快,而是长久以来积压的不满情绪。我同意“一个好的程序员,应该有一颗开放的心,任何语言、任何技术都可为我所用,不带偏见,不拘一格”这样的说法,也是这样的做的。之前在QCon上还和一些朋友谈过我对混合编程的实践和热爱呢(我认为“混合编程”绝对是趋势),而作为一个山寨版的Web 2.0架构师,对于其他平台的各种技术必须得有足够多的了解啊。请大家相信我,我一直在关注其他各种语言/平台/框架(实际上我也一直在结合使用,上次北京俱乐部聚会中我也强调了这方面的重要性),绝对不是井底之蛙——就算还没有变成“王子”,不管怎么说也是个井外的蛙呢。

可惜,对于Java……不用多说了罢。

 

咳咳,好累,好累。大家也一起来讨论,也欢迎大家叫上Java的朋友一起来玩,转载到Java的阵地上也无不可。不过有些东西兄弟我说在前头,一些啥“语言不是关键,没有讨论必要”,“你个死胖子有什么资格评论这些个”这类问题咱就先放放吧,大家在进行讨论的时候记得切中关键,并且看清我已经谈过的东西——咱也要遵循DRY原则嘛。至于如果您还要说我是“MVP鼓吹微软技术”不可信,那还真不怕您笑话,我半夜里辛辛苦苦码上这四五千字,微软不会给我一定点儿额外好处——平时也没有。信不信由您,咱也恨着呐,真的。