为什么总是有人说Java啰嗦,却没人说CPP啰嗦

西部游星 2018-09-07 19:01:40

因为Java只支持面向对象一种编程范式。

只支持一种范式,好处是严谨,风格统一;坏处就是呆板、啰嗦。典型如它的main函数,再也不能像别的语言那样写成一个独立的函数,而是必须包在一个没有实际作用的类里面……

这样“不管有没有必要,反正你必须把任何东西都先弄成类”的要求,显然会导致许多本无必要的间接访问以及由此衍生的其他很多麻烦——和其他语言相比,当然就显得过于啰嗦了。

尤其是早期,相关理论尚未成熟,再加上单一范式的限制,就使得它相对于早已成熟的其他语言,显得表达能力过弱——有一个著名的吐槽,大意就是“之所以Java需要搞出那么多设计模式,就是因为它表达能力太弱,别的语言很简单就能做到的事,它就必须通过设计模式才能拐弯抹角的办到”(当然,这些主要还是面向过程和面向对象风格本身的区别,不能完全算是Java的缺陷)。

与之相反,C++是一种“多范式”语言,非结构化、结构化、面向对象、宏、模板……啥好用你就能得到啥——任何工作,你都有最简化实现它的可能。但缺陷就是,再也没人能“精通C++”——你可以拿它当C用,当Java用,当object-c用,玩模板黑魔法用……但最好别把它当C++用。不然真没人hold得住它。

当年的Pascal也一样:它仅支持结构化编程一种范式,这种纯粹而“板正”的风格使得它成了当时最佳的“教学语言”,但是很少被用到实际项目中。而当年的C,它支持结构化编程,同时也允许你任意解释内存数据。这就使得它得到了额外的许多灵活性,甚至到现在都还充满了生命力。

当然,过去和现在情况还不太一样。

过去的编辑器没现在这么强大、智能;Pascal的“板正”没能带来教学时概念清晰之外的更多好处,反而因为单一范式的束缚让人感觉碍手碍脚,自然不是C的对手。

但现代编辑器强大的语法提示功能给了程序员太大方便——“板正”的单一范式强类型语言的语法提示实在太好做太强大了,你甚至很难把语法错误留到后半拉花括号敲出来之前:付出一点点“格式化”的代价,换来这么大的好处……与之相反,过于灵活随意的C++,它的语法提示可不是一般的难做。

别说200x年前后的“黑暗时代”,哪怕到现在,都还有不少主流编辑器没办法为C++代码提供Java级别的语法提示(我知道现在做的比较好的语法提示,其原理相当于在后台边编译边提示[实际是解析语法树]:而且这个编译器还必须支持“半拉函数”的动态编译,不然很难给出准确的输入建议)。

——亦因此,当年就没人能劝我加入VIM教:在下写C++必用eclipse/VS之类重量级IDE,不然语法提示真没法看(当然,这都是上个年代的老黄历了。现在已经有很多编辑器可以给出高水平的C++语法提示了,甚至可以自动提示模板实例化后的正确参数类型。至于VIM,它很早也已经可以配出基于语法的提示了;不过本人太懒,早年实验几次感觉效果不佳就再也没用它写过C++……)。类似的,由于编译器发展水平所限,过去的Pascal语法“板正”,使得它需要付出很大的额外性能消耗(因为没有办法像C那样让程序员“抖机灵”);而现在的Java,却因为自己的板正,给了字节码编译器以及即地编译器大量的提示,使得它们得以完成深度优化,从而得到了极佳的执行效率……

时代不一样,配套技术成熟度不一样,很多东西就不一样了。总之,没有免费的午餐,诸多相关也不是一成不变的;每一种成功语言之所以成功,都有其道理。评论利弊须就事论事,这才不容易翻船……

C++ 啰嗦,只是吐槽 C++ 啰嗦的人很多早就不在 JAVA 领域,做 Java 的也听不到。

就啰嗦而言 C++ 和 Java 各有千秋。

为什么吐槽 Java 的多,因为 Java 的啰嗦很多时候影响到了业务实现。

如万物皆对象,设个回调、new 个线程、main 个函数,一个指针能搞定的问题非要扯上 class、 interface。满页的set /get 不烦吗? 又比如多值返回,C++ 不支持,但用指针变相实现也很简单,到了 Java 只能包个对象送回去。觉得有引用就够了?写个支持变量和函数绑定的逆波兰试试。

Java 里这类麻烦无处不在。这些繁琐已经渗透到框架和库的方方面面,躲都躲不掉。

加上很多参考的新语言出现,开发者也意识到这类语言设计特点带来的麻烦其实是没必要也没意义的。

C++ 的 include、头文件和衍生的 .d 这些用法都远比 Java 的 import 啰嗦。

C++ 工具链的使用和配置都比 Java 麻烦花样多。五花八门的编译工具,dsl 还要加上 shell、python、lua 脚本,一个个都比 ant maven 难学难用。

考虑跨平台,还得了解各平台各编译器的参数、OS 环境变量、库命名差异、路径差异、宏。

这些方面 Java 比 C++ 简洁很多。

语言本身 C++ 不啰嗦吗?hpp/cpp来回切,函数的前置声明这些也很烦。

指针释放,RTTI,这些 Java 开箱即用的到 C++ 都得造轮子,string,map 这些 stl 提供的很多人会重新造一遍。和 Netty 比 C++ 到现在网络编程这块也没个一统江湖的库。

另外 C++ 开发者用第三方库的态度和 Java 显著不同,写 C++ 的经常可以抠别人几千行代码只为最后能少链一个外部依赖,平白多很多事(而且这种做法很多时候还是对的),写 java 的可以只为用1个函数多加几个链式依赖包也无所谓。

C++ 麻烦的部分像工具链、编译、项目管理基本是一次性负担,还都让 SA 扛了。C++ 做业务因为有指针、宏和灵活到变态的模板,自己的业务代码抽象低写的丑多半是自己的能力问题。复杂又通用的业务,要么个体户大神填了坑,要么微软们早封好了。每个业务域都有大量精短高效只能勉强看懂的代码和精短高效压根全看不懂的代码,想吐槽下也很快就从“语言好烂”的愤慨变成“我好烂水好深”的感慨。加上还有游戏引擎和编译器这两类魔王级项目,你说你业务复杂几百万代码,行摘两段让我们 diss 一下吧。

不是 C++ 不啰嗦,是 C++ 其他痛点和要操心的地方太多,啰嗦的那点事也就不显眼了。加上语言灵活特性多,也容易靠优秀的个体发挥掩盖这个缺陷。

并且 C ++ 已经是原教旨主义范畴的东西,和 VIM 一样,很容易被怼“不是不好用,是你蠢不会用”,而且问题在于很可能还真是。

Java的啰嗦有两个意思,1、在Java代码中存在很多重复,然后又没办法去掉,这里暴露Java抽象能力不足的问题;2、Java的代码很严谨,接口使用什么,很契合设计模式,经常是做一件事情,要沐浴更衣,要繁文缛节,要三请四请,九弯十八曲之后,才轮到正主儿正式登场演出。这是因为在Java是名词的世界,而且类型严谨,所以才搞得这么麻烦。这两个原因纠缠在一块,就搞得Java的代码没法简洁,在猿语中,Java是出了名的啰嗦。

C语言的抽象能力不如Java,但人家是弱类型,人肉类型管理,猿猴高兴的话,随便强制类型转换,就直奔主题去了,Java的礼节规矩问题,在C猿中完全无法忍受,甚至,必要时还可以搞预处理,这可是节省代码的重要手段,虽然很丑陋,但是很管用。很多C开源库的代码,很少体现类型的概念,实在也没法体现,玩的是心惊肉跳惊心动魄。而C#对类型要求也很严谨,但是C#的抽象能力比java高好几个层次,又配套了很多贴心语法糖,基本上可以替换C宏的很多运用,用于精简代码,非常有效。C#的语法设计,似乎骨子里对代码啰嗦很排斥,所有导致啰嗦的地方,都会想心设法搞新语法糖去掉。

而大C++,抽象能力比C#还高一大截,而必要时,猿猴完全可以罔顾类型安全,C语言能Cast的,C++也能随便Cast,const也可以Cast掉,而且,由于C++的类型推导能力很厉害,预处理在C++下又焕发出第二春。C++代码,如果猿猴高兴,如果猿猴呕心沥血,基本上可以去掉代码中所有的重复。更何况,相比于C++本身的复杂,代码啰嗦只是微不足道的一个小问题。

Java就只支持一种范式一种风格,不管你多会用都得罗嗦。而且Java社区无框架不开发的风气加重了Java罗嗦的印象,毕竟按J2EE的风格你Hello个World就得上Spring折腾半天配置了人家C/C++几行代码一句gcc完事呢。

C++抽象能力很强,有各种模板、TMP黑科技,惹急了还有宏,只要你想搞你可以把C++写得很简洁,罗不罗嗦是可选的,至于实现黑科技过程中你写的那一大堆template啊SFINAE什么的,放进namespace detail里对外人来说它们就不存在了,毕竟一大坨detail这能叫罗嗦么,这是C++水平的证明

C++的语法更加复杂,只要灵活使用,确实可以大大简化代码,例如:

C++支持多继承,可以方便的继承多个类的方法。而Java实现类似的功能要使用接口,需要在每个子类实现每个接口方法,非常的啰嗦。

C++支持操作符重载,可以实现很多复杂功能。在Java中,类似的功能需要用函数来实现,非常啰嗦。

C++支持宏定义,可以方便的实现非常复杂,方便,有用的代码模板(并不推荐),而Java没有类似的功能。

不过,这几个语法特性虽然可以简化代码,但要谨慎使用。特别是宏定义,因为难以调试和维护,最好不要用来实现复杂的功能。

但是,Java也有很多方法来简化代码。

Java支持反射。使用反射,可以很容易的实现一些C++中实现起来很麻烦的功能。

Java中,可以使用annotation和反射来自动生成代码,可以大大简化编程。

本页共43段,3952个字符,10489 Byte(字节)