扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
我以前写Java,最近主要写Ruby,以及一点点JavaScript。
成都创新互联公司服务电话:18982081108,为您提供成都网站建设网页设计及定制高端网站建设服务,成都创新互联公司网页制作领域10年,包括成都LED显示屏等多个方面拥有多年的网站运维经验,选择成都创新互联公司,为网站锦上添花。
我觉得文章中有几点,是很可取的:
编程使用什么工具是重要的,然而工具终究不如自己的技术重要。很多人花了太多时间,折腾各种新的语言,希望它们会奇迹一般的改善代码质量,结果最后什么都没做出来。选择语言最重要的条件,应该是“够好用”就可以,因为项目的成功最终是靠人,而不是靠语言。
很多时候我们忙于学习不同的语言,而忽略了语言的最终目的,是写出可以解决问题的程序。
IntelliJ还可以进行非常迅速的结构变换,这让你就像艺术家在构造一个雕塑作品。最开头我可以大刀阔斧,把代码劈成大致的形状,然后再把它仔细推敲,揉捏成更好,更容易理解,更具魅力的形状。
是的。用IntelliJ来Refactor Java代码的体验,的确比 用RubyMine来Refactor Ruby代码、用WebStorm来Refactor Javascript代码的体验,要好太多太多了。虽然后者的体验也强于用Vim时候的体验,但用IntelliJ来的更加畅快淋漓,而且从来不用担心因为Refactor而出现命名错误(如果不用Reflection的话)。
很多人讨厌Java,其实是因为早期的GoF Design Patterns,试图提出千篇一律的模板,给程序带来了不必要的复杂性。然而Java语言本身,其实跟Design Patterns并不是等价的。Java的设计者跟Design Pattern的设计者,完全是不同的人。你完全可以使用Java写出非常简单的代码,而不使用Design Patterns。
我自己对于一些大公司规定的模式,比如“Programming towards Interface, not implementation”十分反感——这样子造成了很多interface,只有一个implementation;而在读代码的时候,就要跳转很多个文件,才能找到需要的内容。但我觉得这是写代码的人得问题,和Java无关。只是很多人在写Java的时候,太从字面上理解“Programming to Interface”了。
然后我不太同意的:
Python凑合可以用在不重要的地方,Ruby是垃圾,JavaScript是垃圾中的垃圾。原因很简单,因为Ruby和JavaScript的设计者,其实都只是民科。
我个人很喜欢Ruby的设计的,主要来自于MetaProgramming的部分——真的可以让代码量少很多。来自于更高级别抽象的代码量减少,直接意味着,整个程序变得更容易阅读和理解。我不觉得民科设计出来的东西,就意味着这个东西不好。而且Ruby程序,debug起来还是很容易的:RubyMine对于断点StepTrace也有很好的支持。而且,因为是Script Base的语言,可以很容易的去阅读/修改Library的代码,从而很快地理解对应的Library。
JavaScript还是有些坑的,比如没有原生的Class(ES6的class看起来只是function的一个syntax suger)、神奇的prototype和this的关系问题;但理解了原理,这些坑还是挺容易避免的。而且也有很多用JavaScript开发的不错的App和框架,异步编程的思想也很好(当然 思想这种东西,都任何语言都是可以支持的)。“垃圾中的垃圾”就太偏颇了。
对于Go / Scala / Clojure我几乎没有了解,无法评论。
然后讲一下,我对于Java很反感的地方:长,function不是object。
1. 依稀记得 当年写各种Data Access Object,里面有若干Getter / Setter,虽然用IDE可以自动生成Getter和Setter,但依然……读起来/维护起来 很辛苦。
2. 以前写Android程序,加EventListener。其实只是一个function而已,但只能通过Anonymous Class、在里面define function的方式——加一个EventListener,2层缩进就出去了。让代码变得好丑。
(在Java8里面,支持了Lambda,应该有所缓解吧;这里我还不是很清楚)
java是面向对象语言,王垠的40行代码是scheme写的~,没学过函数式语言还是不要试图去理解了。
我先必须指明,楼上的回答都是错误的或者不明确的,当你把String换成一个不可拆箱的对象时,就是指向地址,而不是值了,至于JAVA基础数据类型到底是不是真正的值类型,
这个问题对于很多java初学者来说都存疑过,我觉得解答的最好的是王垠的一篇文章。
我先贴出原文地址:网页链接
Java 有值类型,原始类型 int,boolean 等是值类型,其实是长久以来的一种误解,它混淆了实现和语义的区别。不要以为 Java 的官方文档那样写就是权威定论,就可以说“王垠不懂” :) 当你认为王垠不懂一个初级问题的时候,都需要三思,因为他可能是大智若愚…… 看了我下面的论述,也许你会发现自己应该怀疑的是,Java 的设计者到底有没有搞明白这个问题 :P
胡扯结束,现在来说正事。Java,Scheme 等语言的原始类型,比如 char,int,boolean,double 等,在“实现”上确实是通过值(而不是引用,或者叫指针)直接传递的,然而这完全是一种为了效率的优化(叫做 inlining)。这种优化对于程序员应该是不可见的。Java 继承了 Scheme/Lisp 的衣钵,它们在“语义”上其实是没有值类型的。
这不是天方夜谭,为了理解这一点,你可以做一个很有意思的思维实验。现在你把 Java 里面所有的原始类型都“想象”成引用类型,也就是说,所有的 int, boolean 等原始类型的变量都不包含实际的数据,而是引用(或者叫指针),指向堆上分配的数据。然后你会发现这样“改造后”的 Java,仍然符合现有 Java 代码里能看到的一切现象。也就是说,原始类型被作为值类型还是引用类型,对于程序员完全没有区别。
举个简单的例子,如果我们把 int 的实现变成完全的引用,然后来看这段代码:
int x = 1; // x指向内存地址A,内容是整数1
int y = x; // y指向同样的内存地址A,内容是整数1
x = 2; // x指向另一个内存地址B,内容是整数2。y仍然指向地址A,内容是1。
由于我们改造后的 Java 里面 int 全部是引用,所以第一行定义的 x 并不包含一个整数,而是一个引用,它指向堆里分配的一块内存,这个空间的内容是整数 1。在第二行,我们定 int 变量 y,当然它也是一个引用,它的值跟 x 一样,所以 y 也指向同一个地址,里面的内容是同一个整数:1。在第三行,我们对 x 这个引用赋值。你会发现一个很有意思的现象,虽然 x 指向了 2,y 却仍然指向 1。对 x 赋值并没能改变 y 指向的内容,这种情况就跟 int 是值类型的时候一模一样!所以现在虽然 int 变量全部是引用,你却不能实现共享地址的引用能做的事情:对 x 进行某种操作,导致 y 指向的内容也发生改变。
出现这个现象的原因是,虽然现在 int 成了引用类型,你却并不能对它进行引用类型所特有(而值类型没有)的操作。这样的操作包括:
deref。就像 C 语言里的 * 操作符。
成员赋值。就像对 C struct 成员的 x.foo = 2 。
在 Java 里,你没法写像 C 语言的 *x = 2 这样的代码,因为 Java 没有提供 deref 操作符 *。你也没法通过 x.foo = 2 这样的语句改变 x 所指向的内存数据(内容是1)的一部分,因为 int 是一个原始类型。最后你发现,你只能写 x = 2,也就是改变 x 这个引用本身的指向。x = 2 执行之后,原来数字 1 所在的内存空间并没有变成 2,只不过 x 指向了新的地址,那里装着数字 2 而已。指向 1 的其它引用变量比如 y,不会因为你进行了 x = 2 这个操作而看到 2,它们仍然看到原来那个1……
在这种 int 是引用的 Java 里,你对 int 变量 x 能做的事情只有两种:
读出它的值。
对它进行赋值,使它指向另一个地方。
这两种事情,就跟你能对值类型能做的两件事情没有区别。这就是为什么你没法通过对 x 的操作而改变 y 表示的值。所以不管 int 在实现上是传递值还是传递引用,它们在语义上都是等价的。也就是说,原始类型是值类型还是引用类型,对于程序员来说完全没有区别。你完全可以把 Java 所有的原始类型都想成引用类型,之后你能对它们做的事情,你的编程思路和方式,都不会因此有任何的改变。
从这个角度来看,Java 在语义上是没有值类型的。值类型和引用类型如果同时并存,程序员必须能够在语义上感觉到它们的不同,然而不管原始类型是值类型还是引用类型,作为程序员,你无法感觉到任何的不同。所以你完全可以认为 Java 只有引用类型,把原始类型全都当成引用类型来用,虽然它们确实是用值实现的。
一个在语义上有值类型的语言(比如 C#,Go 和 Swift)必须具有以下两种特性之一(或者两者都有),程序员才能感觉到值类型的存在:
deref 操作。这使得你可以用 *x = 2 这样的语句来改变引用指向的内容,导致共享地址的其它引用看到新的值。你没法通过 x = 2 让其他值变量得到新的值,所以你感觉到值类型的存在。
像 struct 这样的“值组合类型”。你可以通过 x.foo = 2 这样的成员赋值改变引用数据(比如 class object)的一部分,使得共享地址的其它引用看到新的值。你没法通过成员赋值让另一个 struct 变量得到新的值,所以你感觉到值类型的存在。
实际上,所有的数据都是引用类型就是 Scheme 和 Java 最初的设计原理。原始类型用值来传递数据只是一种性能优化(叫做 inlining),它对于程序员应该是透明(看不见)的。那些在面试时喜欢问“Java 是否所有数据都是引用”,然后当你回答“是”的时候纠正你说“int,boolean 是值类型”的人,都是本本主义者。
1.这段 40 多行代码是给 Scheme 程序脱糖的程序,属于解释器的代码,而不是应用代码。对其的客观评价显然只有设计解释器的人才能给出。
2.这代码不是一般人看的,本身他用的语言就是极客向的语言,而且这搞的又是很专业的东西,主要是与解释器相关的领域。CPS的功能是很明确的,但其价值只有对编译器解释器很有研究的人才能判定。
3.以自然语言写作比喻,编写自解释器级别的代码,就像你在写一本小说,而小说的主角也在写一本小说,这位主角在描写你,对你的刻画会影响到你,你受到影响之后又会改变小说中的主角,从而影响到他对你的描写。你俩要相安无事,情节合符逻辑地发展,直到最后圆满的结尾。这比写一本普通小说可难多了。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流