【供批判】所谓的java十宗罪

某日于CSDN论坛上看到的~~ 大家瞅瞅

附原帖地址:http://topic.csdn.net/u/20110617/15/e9393695-c35b-480e-90e0-6ab74ae29737.html

java十宗罪


好吧,我知道看这标题很多人就忍不住要拍砖或表示不赞同了,我都接受。

我在遇到问题时,找一些搞java朋友求助,有能解决的,我想说的是不能解决的情况下,他们大多会说:“你怎么能这么弄呢?这么搞是不行的,你首先在思路上就错误了,我们从来就不这么做。”,比如“我们一般很少用存储过程,你用这么多存储过程,我建议你使用hibernate代码实现你的业务,而不是用存储过程”,这个问题是在我遇到用hibernate调存储过程时发生一些状况后,我一个搞java的朋友也无法解决时,他如此说道。
java开发人员还喜欢说:这个不应该由jdk或某某框架完成,而应该是由勇敢、勤劳、智慧的您来编写实现的。

以下都是我在开发java项目时,遇到的一些问题,可能也有写得不对的地方,望指正。
遇到很多问题,一时间无法全部拿出来讨论,就随便列举了几条。

1."abc"=="abc"返回的结果是false,很多初学java的都要在这个问题很浪费很多时间,因为会非常自信的以为这里会返回true,根本不会想到原来问题出在这里。网上看到有贴子讨论过这个问题,说什么java是纯面向对象的语言,==操作符是比较地址什么的,而"abc"是引用,所以不能使用==操作符进行比较,而应该使用equals方法来进行比较,会犯这种错误的,多半是因为自己基础不牢,却还来说java的不是。我看到一个人说的一个例子,很能表示我的感想,是这么说的:有一天我去到一个餐厅,因为餐厅门口有一滩水,导致路面很滑,我不小心摔倒了,于是我找来餐厅经理,追究其责任,结果餐厅经理告诉我,这是因为我自己走路的姿势不对,所以滑倒了,与餐厅无关。

2.为什么没有get;set;属性,而是使用getXX();setXX()方法来代替,反射难道不要成本吗?
  我所了解到的struts/spring/hibernate里都大量用到这种方式,比如struts中的vo对象,里面若有个getUsername(),在页面里可以用<s:property value="username"/>来取值,这中间我想应该是用反射来找到getUsername()方法,再取得其值的吧,同样的spring/hibernate中也大量用到这种方式,我想问,反射不是说很低效的吗?

3.做个自定义标签还要自己写个tld配置文件,有时在看一些java的相关书籍上面提到零配置时,我就觉得非常可笑,不知道所谓零配置的精神到底体现在哪里?也许写个配置文件也并没有那么难,但关键问题在于,从技术上来讲这个tld明显是可以不要的啊,tld里面主要就描述了这个tag叫什么名字有哪些属性,分别是什么类型,这些信息完全可以在类里面表示,只要是实现Tag接口的类就被自动识别为自定义标签这样不好吗?通过识别类里有哪些getXX();setXX();(更好的方案是有get;set;属性)来确定这个自定义标签有哪些属性,又分别是什么类型这样不好吗?为什么还要多此一举搞个tld配置文件?
  还有个问题是,如果我写了个MyTag的类,继承了某个自定义标签类,我还要为MyTag写个相应的tld配置,我不知道将来还有没有其他开发人员会继承我的MyTag,也许就算我热烈欢迎别人来继承我的MyTag,但当别人看到我MyTag里近三四十个getXX();setXX();之后,想到要为其写上相应的tld配置文件而望而生怯吧。

4.数据访问在我看来,应该是个很简单的事情,简单来就,就是执行SQL语句,复杂一点,就再加上实体映射,所有框架解决的问题,首先就是要易于使用,在使用过hibernate之后,我感觉它太复杂了,我在.net里有一个数据访问层,只需要在指定的配置文件中配置连接字符串,就可以在程序中的任何地方调用DbHelper.Execute(sql)、DbHelper.ExecuteDataSet(sql)、DbHelper.ExecuteDataTable(sql)了,使用起来非常简单,当然也有实体映射,DbHelper.save(entity)、DbHelper.delete(entity or key)、DbHelper.select(条件)这一组方法就可以操作实体对象,select返回的是实体列表,实体通过元属性设置其关联的表和字段,这中间除了连接字符串之外,是没有任何其它配置文件的。相比之下,hibernate咋需要这么多配置文件?我知道hibernate也可以配置注解,就不需了hbm配置文件了,但即使这样,据我了解依旧还是需要很多除连接字符串之外的其它的相关配置文件。

5.话说java也有这么多年了,hibernate也有这么多年了,到底是我不会用,还是它真的就是这样的,hibernate对于存储过程的支持,实在让我抓狂,居然不支持存储过程,在网上寻找hibernate调用存储过程,得到的答案多数就是越过hibernate,而仅仅从hibernate中取得一个connection,再使用jdbc的方式调用存储过程,这样做存在一个问题,事务不能得到控制了,由于我还比较水,hibernate的事务控制又是暗箱操作的,好像是只要在service层中写的业务代码就都在一个事务中,所以我无法让我的存储过程调用和hibernate业务代码串在一个事务当中,而很多情况下,我是想要让它们一个失败就全部失败的。
  除此之外,也有不越过hibernate而调用存储过程的办法,有两个,也是要写配置文件,一个是必须要有返回的结果集,我就很纳闷,为什么一定要有结果集,我的很多存储过程就只是处理一些数据,不需要返回结果集的,最难受的是oracle的存储过程其实不支持返回结果集,必须使用一种变态的游标方式返回,这么做我会感觉到极其反胃。另一个办法是通过修改实体在insert/update/delete时的默认行为,比如我在insert一个员工时,本来应该是执行sql语句insert into employee values (?,?,?,?)的,我可以通过配置文件修改这个默认行为,改成{call myproc(?,?,?,?)},这种方式显然也不是我想要的,我只想调用一个存储过程,执行一个业务的处理。以上两种方式是会被暗箱操作的事务所管理的,但并不能满足我的需求,我要怎么办?

6.数据访问的结果集对象ResultSet、RowSet、CachedRowSet等没有得到广泛的应用,各个框架更多的是倾向于支持实体列表,这么做导致出现一个问题,那就是我只能返回已知结构的结果集,若想要临时返回个东西还必须要在实体中添加相应的属性getXX();setXX();方法,比如在hibernate中,要访问员工表,员工表中本来只有部门ID,没有部门名称,你想要有部门名称,就必须在员工实体中添加一个deptName的属性,要所有的结果都是已知结构的,这样很痛苦,如果不返回到实体列表中,也可以返回到 ArrayList<Object[]> 中,但这样的数据没有列名称,不明白为什么不直接查询到ResultSet中,然后让更多的框架支持ResultSet,比如struts,在写页面使用struts标签时,可以像操作实体列表一样操作ResultSet。
<s:iterator id="myResultSet">...</s:iterator>,(还是本来就支持,只是我不会?那就不好意思啦!)只是希望让更多的框架支持未知结构的结果集,让程序员事先设计好结果集的结构是很累人的,就算是代码生成,也只能生成数据库里的每一张表对应的实体,但往往我们需要select unkownSchema from myTable得到未知结构的结果集,并不是每次都select *。

7.再说ResultSet,之所以不直接用这个,而使用实体列表来代替,我想是不是也间接的说明了,ResultSet这个类不方便使用,.net中的DataSet和DataTable就得到大量使用,因为它们方便好用实用。可能最大差别的地方就在于,DataSet是断开式的存在于内存中的微型数据库,而ResultSet只是连接式的数据库读取器,相当于.net中的DataReader,必须保持连接才能读数据,我知道有CachedRowSet可以断开式的存储数据在内存中,好吧,这个就不是问题了。但另一个问题在滋扰着我,做为存储结果集的容器,提供给我们操作这个结果集的方法太少了,甚至取得该结果集的总行数的方法,我们都需要开动小脑筋,这么写:rs.last(); int count = rs.getRow(); rs.first() 负责的话,它需要至少三句代码才能取到总行数。也许这只是小问题,这个或许应该由勇敢、勤劳、智慧的我们来实现。

8.在我看来,struts最大的意义在于,它使得每个jsp页面都有了一个与之对应的java类的方法,也就是那个action方法。你一定会跟我说,struts的功能并不只如此,但我说,我见过的很多(小公司)的项目,struts的意义就只是这样的,我想像在我们国家,还有成千上万的使用java技术的公司,struts对于他们的意义,也就是让jsp有了后台代码。如果仅仅只是如此,为何不由官方提供,直接让jdk支持,让struts的先进来弥补jdk的落后吗?只会欲盖弥彰。
  或者你会说,即便struts就是提供了让每个jsp页面都有一个与之对应的action方法,这也非常伟大了,做到这一点,已经彻底改变了人们开发web项目的方式,由原来的业务代码和页面混在一起,变成解偶分离,非常成功了。我想说,不要拿你十年前的荣耀到今天再来说了,已经out的不行了。

9.再说myeclipse,这个ide在java体系中几乎成为标准,我见过的所有java开发人员都是使用这个IDE,但相比之下,它与visual studio就相差太多了,性能就不说了,如果不做优化,那是慢得想死,话说为什么不能在其一发布出来的默认设置就是最优化的呢?如果我们需要什么插件组件,再自己加载,这样不是更清楚明白吗?
另外myeclipse的插件安装方式实在让我汗颜,6.x,7.x,8.x这几个版本的插件安装方式各不相同,我在想,为什么不能直接双击安装?vss2005就是直接双击安装。至今我还没搞清楚svn插件怎么安装的,好吧,我是很水,那个插件的安装有时要复制文件到指定目录,有时要启动myeclipse之后,选择help菜单下的software updates,有时候又要选择什么myeclipse configuration center,有时候要连接互联网在线操作,更甚者,给你个java文件,要你编译成class文件,再按步骤操作,我是服了。


10.out输出参数,部分类,扩展方法,lamuda表达式这些非常好的东西,java都没有,还是我不会吗?望指正。
  spring,其实我现在还不知道它是干嘛的,好吧,这是我的罪。

望展开激烈、火爆的讨论,可以使用分庭伉礼、围魏救赵、十面埋伏、单挑、围殴等各种手段。

 

 

 

 

---------------------------------------------------我是神码你知道-----------------------------------------------------------

某人拙见~ 献丑供各位大牛批判~~

1、LZ没有理解真正面向对象的真义,不解释

2、我其实没懂LZ的意思~ 其实,对于JAVA来说,最重要的不是性能,不讨论反射是否低效,其本身的存在的意义使得java的面向对象的性质更加自洽与完备,因为反射的本质其实是将类也作为了一个对象(这个有点绕,自行参详)。如果没有反射,java本身的面向对象逻辑上就是不完备的。参考java classloader机制,反射是java面向对象精髓所在。

3、同意,我也很烦tag  不过这个关java什么事情?

4、同意,我也很讨厌配置文件 不过这个关java什么事情?

5、hibernate调用存储过程不是很清楚,但是hibernate对于事务控制还是很方便的,当然这个也可能是经验不足,毕竟很少做web,不过这个关java什么事情?

6、不懂~ 但是还是想说 这个关java什么事情?

7、LZ其实是在吐槽框架吧? 关java什么事情?

8、确实对于大多数开发者来说struts意义在于此,但是servlet+jsp一样可以写出MVC的代码结构,说到底这是设计问题,不是语言问题。

9、谁说myeclipse是标准?LZ其实都是在做web开发吧?首先喜欢vs的程序员一定是个懒惰的程序员,他们都讨厌配置环境(当然我也是),研究IDE,总觉得默认的都是最好的,非到万不得已不会改变。然后,对于java来说最好的工具是ecilpse,凡是myecilpse能够做到的,都可以通过ecilpse+插件的形式做到,而myecilpse的慢在于他里面你80%的东西可能都不会用到,其实我想反问一句,难道vs不慢?要快,请用notepad/vim/emacs+ant/maven/makefile。而对于ecilpse本身,可以通过插件的方式个性化的扩展,保证功能的同时也保证了性能。BTW我觉得其实IDE这个东西没必要争,你觉得最顺手的就是最好的。

10、这个一个一个说,

        out输出参数:

       我查了一下这是C#里面改变函数传入参数值的一个方式(还有一个是ref),首先我个人觉得在函数里面通过改变参数的值来返回值的方式本身就是一种很原始的方法。对于面向对象设计语言,这种方式改变参数值会是一种罪恶。

        比如 void nime(A a,MM b,A c,XX d); 对于这种方式,首先必定是函数参数数量的增长,我觉得大多数人初学WINDOWS编程的时候肯定都会被那一堆参数列表吓到吧?其次对于一个函数来说,传入参数的职责应该仅仅提供其本函数本身处理对象,我们又要让他去返回值个函数处理的结果,那返回值意义何在?在这样的高级语言中,我觉得这种方法是不可容忍的。为什么说C#比JAVA更加先进,其实就是因为他考虑到了程序员(尤其是C/C++)可能的这种坏习惯,通过显式的方式告诉程序员,在参数列表里面哪些参数用于传递引用,哪些参数用于返回结果。这其实是为了适应程序员的坏习惯,而非什么特性。

       退一万步说,难道java就不允许这种机制么?对于一个对象的引用,难道不能在方法体中改变对象的成员么?只是java没有显式的标识出来而已。LZ口出此言,原因同一,不解释。

 部分类:

      先来看一下定义:

       Partial Class,部分类 或者分布类。顾名思义,就是将一个类分成多个部分。比如说:一个类中有3个方法,在VS 2005将该类中3个方法分别存放在3个不同的.cs文件中。

      怎么说,我觉得这个特性,如果是是要写库/框架 会是很有用的。但是如果你是做开发Big class不是应该尽量避免么?当然也不绝对。从某种意义上来说这只是一个tricks。有当然会方便一些,但是没有却不至于硬伤。

 

扩展方法:

       这个确实了解不多,不过应该是动态语言的特性吧?C#里面支持但是其实其应用是有很大限制的,比如不能调用原有方法的的私有成员等,其实又回到上面,这是C#比JAVA先进的地方,但是并不能说是java的过错。更谈不上罪。

lamuda表达式:

      这个貌似是C#从函数式编程语言里面引入的特性?我没怎么看懂,但是觉得极大的降低了程序可读性,仅仅是个trikes而已。为什么要算是罪呢?

----------------------------------------------------妹的你肿么又出现了------------------------------------------------------

果然应了这样一句,论坛里面去争论哪种语言好哪种语言坏的人都不会是高手。大家可以去看后面的回帖,真是各种奇葩不解释。

最后一句:语言是浮云 思想最重要。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值