Archive

Archive for the ‘translation’ Category

(翻译)Handling null in Java

March 24th, 2010 No comments

原作者:Roy van Rijn
原文地址:http://www.redcode.nl/blog/2010/02/handling-null-in-java/

空值处理是我在jee的项目中遇到的最常见的问题. 但为什么这会是个问题呢? 接下来我们又准备选用何种策略来解决这个问题呢? 在这篇文章中我将尽力找出这个答案.

让我们先来看一段商业逻辑代码,并且我们假设没有空值:

         public BigDecimal getBalance(Person person) {
	    Set<Account> accounts = person.getAccounts();
	    BigDecimal totalBalance = BigDecimal.ZERO;
	    for(Account account: accounts) {
	        totalBalance = totalBalance.add(account.getBalance());
	    }
	    return totalBalance;
	}

这看起来非常的好理解! 但是这不是我们大多数项目中的情况. 通常我们看到的代码是这样:

         public BigDecimal getBalance(Person person) {
	    if(person != null) {
	        Set<Account> accounts = person.getAccounts();
	        if(accounts != null) {
	            BigDecimal totalBalance = BigDecimal.ZERO;
	            for(Account account: accounts) {
	                if(account != null) {
	                    totalBalance = totalBalance.add(account.getBalance());
	                }
	            }
	        }
	        return totalBalance;
	    } else {
	        return null;
	    }
	}

呵呵,这看起来一点也不漂亮! 我们如何去改进呢?

Inversion of logic
第一个策略可以根据我之前写的文章inversion of logic(http://www.redcode.nl/blog/2009/12/inversion_of_logic/). 这里的思想是先退出, 这将提高这个方法的可读性. 让我们看看更具这个原则改进后的代码:

         public BigDecimal getBalance(Person person) {
	    if(person == null || person.getAccounts() == null) {
	        return null;
	    }
	    Set<Account> accounts = person.getAccounts();
	    BigDecimal totalBalance = BigDecimal.ZERO;
	    for(Account account: accounts) {
	        if(account != null) {
	            totalBalance = totalBalance.add(account.getBalance());
	        }
	    }
	    return totalBalance;
	}

这看起来好一点了,简短些,但是还是有我们不想要的”!=”和”==null”的检查

Code by contract
避免空值检查的最好方式是在你的应用中避免空值. 只需要在你的所有的方法返回时非空! 这听起来非常容易并且直接,但是做起来比听起来要困难一些,因为每个方法返回非空并不是我们的习惯.
令人欣慰的是目前有些ide已经实现了@NotNull和@Nullable这两个annotations. 有了这两个annotations你可以通知其他的程序员,你的IDE及代码分析工具:你创建你的方法时的思想:

         @Nullable
	public Person getPerson(Long id) {
	    return something.retrievePerson(id);
	}
 
	public void printPersonName(Long id) {
	    Person person = getPerson(id);
	    System.out.println(person.getName());
	    //Causes warning: getPerson is Nullable, thus this is a possible NPE!
	}

它也可以帮助你清楚的声明,你的方法调用中,参数person非空:

         public void printPersonName(@NotNull Person person) {                
	    System.out.println(person.getName());                        
	    //Very good, we know we won't get a NPE here!                
	}                                                                
 
	public void executeThis() {                                      
	    Person person = null;                                        
	    printPersonName(person);                                     
	    //Causes warning: person might be null, thus can cause a NPE!
	    //Code analysis tools and/or IDE will warn you about this.   
	}

它也可以帮助你修正可能的编码错误:

        @NotNull     
        public Person getPersonFromDatabase(@NotNull Long id) {                            
	    //Use JPQL                                                                     
	    Query query = em.createQuery("SELECT p FROM Person p WHERE p.id = :value");    
	    q.setParameter("value", id);                                                   
	    return q.getSingleResult();                                                    
	    //The IDE will complain about this.                                            
	    //The database might return null, we don't allow returning null in this method.
	}

使用这个方法你多了几分把握. 但是这不是万全之策. 我们必须停下来想一想,空值是从哪里来的?
事实上,当时停止返回空值的时候(这取决于你和你的团队),仍旧有一些没有检查的情况. 例如你使用的外部的apis,框架,ORM-mapper. 所以每次执行非你写的方法的时候,你仍旧不得不手工检查. 但是你务必要做到这一点. 而后的代码你可以不做检查,因为你使用了@NotNull这个annotation. 假如你对上面的Person对象及所有fields这么做了,那么你可以是第一个例子的代码变得漂亮,干净很多. 没有空值检查,它们由annotation约束. 唯一要做的就是添加参数的信息.

        @NotNull
	public BigDecimal getBalance(@NotNull Person person) {
	    Set<Account> accounts = person.getAccounts();
	    BigDecimal totalBalance = BigDecimal.ZERO;
	    for(Account account: accounts) {
	        totalBalance = totalBalance.add(account.getBalance());
	    }
	    return totalBalance;
	}

在我的经验中,这样做很不错, 我已经这样做了有超过一打的次数,甚至在@NotNull和@Nullable出现之前. 在这两个annotations出现之前,我们就在javadoc里添加这样的信息, 但是随着IDE检查的出现,这样的做法就不变得容易很多.

Null object pattern
使用一个null-object是与coding-by-contract的方式完全不同的门路. 这种思想背后的模式是不返回空对象,代替的是返回一个真的对象. 我们的例子就会变成这样:

        public interface Person {                                                                          
 
	    String getName();                      
	    void setName(String name);             
 
	    List<Account> getAccounts();           
 
	    //..etc..                              
	}                                          
 
	public class NullPerson implements Person {
 
	    public String getName() {              
	        return "";                         
	    }                                      
 
	    public void setName(String name) {}    
 
	    public List<Account> getAccounts() {   
	        return Collections.emptyList();    
	    }                                      
	}

这样做后,巨大的好处是你在调用person.getName()的时候是永远安全的,因为即使你得到一个NullPerson,但这个对象也早就存在了. 这个Null-Object很明显是个单例.

         public BigDecimal getBalance(Person person) {
	    Set<Account> accounts = person.getAccounts();
	        //NullPerson returns empty list, no more NPE!
	    BigDecimal totalBalance = BigDecimal.ZERO;
	    for(Account account: accounts) {
	        totalBalance = totalBalance.add(account.getBalance());
	    }
	    return totalBalance;
	}

关于这个模式的更详细阐述,但更一般的版本是由martin Fowler的special case pattern(http://martinfowler.com/eaaCatalog/specialCase.html). 这里不只有一个Null-special情况,你也可以扩展:

        public class UnknownPerson implements Person {
 
	    public String getName() {
	        return "";
	    }
 
	    public void setName(String name) {}
 
	    public List<Account> getAccounts() {
	        return Collections.emptyList();
	    }
 
	}
	public class InvalidatedPerson implements Person {
 
	    public String getName() {
	        return "";
	    }
 
	    public void setName(String name) {}
 
	    public List<Account> getAccounts() {
	        return Collections.emptyList();
	    }
	}

现在你可以返回更多信息,而不只是一个无意义的”null”!

这种模式也有一个问题. 它也没有解决你的问题. 为什么我们会想要计算一个NullPerson的账户总结余呢?当你取得一个person并且是一个NullPerson实例的时候,捕获且适当的处理,而不是一味的继续下面的代码.

Safe null operator
有一段时间,有一种思考,就是通过Coin项目把Safe-null-operator引入java7中. 假如你有Groovy的编程经验,那么你可能见过以下的代码:

         public String getFirstLetterOfName(Person person) {
	    return person?.getName()?.substring(0, 1);
	}

这个思想就是用”?.”来替代”.”. 这个引号标志意味着”假如我们将要访问的对象是空,那么返回空,否则执行下一个方法”.
那么在这个例子中:
假如person为null,那么返回null
假如getName()为空,返回null
最后返回substring(0,1)的结果

假如写成目前的代码形式就是这样:

         public String getFirstLetterOfName(Person person) {
	    if(person == null) {
	        return null;
	    }
	    if(person.getName() == null) {
	        return null;
	    }
	    return person.getName().substring(0, 1);
	}

你也可以返回一个默认的值:

         public void printName(Person person) {
	    System.out.println(person?.getName() ?: "Anonymous");
	}

假如perrson或者getName()是空,那么”?:”操作符就返回默认的字符串.
这看起来非常的不错吧,哈?唯一的问题是,这样的新操作符最终没有被引入到Java7的变更列表中.
有趣的是:你知道为什么”?:”操作符被称为”猫王”操作符么?从侧边看起来它像猫王的一个笑脸,包括他大圈的头发!

Categories: translation Tags: , , ,

[翻译]Top 5 trends and technologies in software development

March 5th, 2010 No comments

不翻译了,有兴趣自己看原文,地址:http://blog.mostof.it/top-5-trends-in-software-development
在目前多变的软件开发的世界中,保持对当前技术,方法,趋势的了解是极其重要的. 但这不是那么容易就能做到的,简单的,不是每个人在工作和生活的同时还拥有足够的时间学习这些新玩意. 因此选择是关键,巧妙的选择一些进行学习,这样就不会错过一些重要的东西,而且也可以让我们远离那些垃圾或不重要的趋势.
我写了这篇文章列举了一些小的甚至不完整的事项, 我觉的这些是我要关心和实践的. 有些可能已经陈旧的,但是还没有充分的掌握.

1: Learn and use a modern scripting language
学习并使用一种现代的脚本语言,如:Ruby,Python,Groovy

2: Learn thogoughly and embrace the philosophy of a modern version control system
学习,拥抱现在代版本可控制的理念,如:svn,cvs

3: Be familiar with NoSQL solutions like MongoDB, CouchDB
熟悉NoSql的方案,如MongoDB,CouchDB

4: Learn a functional language – or more than one
学一些功能性的语言,如:Erlang

5: Study agile methods and concepts
学习敏捷开发的方法和思想,如:
TDD-Test Driven Development 测试驱动开发
iteration-based development 迭代开发
BDD-Behavior Driven Development 行为驱动开发
XP-Extreme Programmingn 极限编程
CI- Continuous Integration 持续集成
Scrum

Categories: translation Tags:

[翻译]On the road to being a better developer

March 5th, 2010 No comments

[翻译]On the road to being a better developer
原文地址:http://blog.mostof.it/being-a-better-developer
每个人都想在其所在的岗位上做的出色,这是人类的本性,这就是为什么我们会成长. 关键是持续不断的提升,不因小的失败和过程中的起起落落而失望. 在过去的10年中,我作为一个开发者,我认为我已经学到很多有价值的经验,许多是可以应用到生活和工作的其他领域. 现在我将与你分享我的经验.
以下没有特定的顺序:
Lesson #1-See the big picture(关注大局)
在细节上容易迷失方向,专注于小事而丢掉了重点和方向. 整体总是超出它的所有部分的总和. 即使你是个刚入行的程序员,尽量关注项目的其他方面,如,商业,沟通,尽可能的多的方面. 当你把这个工作作为你的专业时,编码是欧莱雅艺术而艺术不再欧莱雅 – 它有一个理由,一个目标。我们的目标绝对不是’完成编码任务’. 它是和在敏捷开发中的”done done”的概念是同一个事情,即:一个项目只有经过了测试,被人认可,健康的,再经过压力测试和回归测试后才算完结. 最后的测试应该较少的注重技术方面,而应该把更多的精力关注与操作,利益,品牌建设和客户满意度. 在这样的方式下获得成功,你的视野中必须始终拥有项目的全局目标.

Lesson #2-Take your time(慢慢来)
这听起来是容易,自然的,但是这通常是很困难的,当deadline逼近的时候. 不要追求速度,速度会带来重点的丢失和疏忽,制造bugs. 在后期你要花费大量的时间,精力及情绪. 速度自然而然的来自于好的设计和架构的选择及解决方案,另外加上经验和熟练程度. 这些事你不可能在匆忙中得到. 请注意,它已无关懒惰或者挑灯夜战,那些都是坏习惯.

Lesson #3-When things go wrong, be ready for a paradigm shift(当出乱子的时候,做好转变的准备)
这也需要时间和经验,但这是宝贵的东西. 当目前的技术和方案变得缓慢或不可用时,你应该停止用旧的方式解决新问题,应该寻找替代方案. 近期的NoSql运动就是这样一个例子(什么是NoSql?如:google的bigtable, apache的hadoop). 但是当旧的方案被证明还是有用的时候,不要用目前炒作的,流行的lib或软件. 假如你的好的旧的关系型数据可以很好解决你的问题,那么就没有理由使用NoSql服务. 同样的对于函数式语言,如果只是因为你可以有一个更完美的解决方案的话,就不要在你的代码库里引入新的语言. 从另一面来说,你的面向对象的方式不能自然的,不能有效的解决你的问题,那么去找一个功能性的方法. 为此,保持对新趋势的了解,阅读一些新技术的文章,至少每周一次.

Lesson #4-Keep your brain trained(保持大脑思维能力)
不要满足于日常的工作,做一些额外的训练. 可以到codegolf或Eler项目的网站上找一些问题,想出尽可能多的解决方案,然后比较他们. 也可以练习算术,特别是状态,图形和集合的理论. 当你遇到一些复杂的算法问题,他们可以真正拯救你. 作为一个开发者不要在下班后就停止与其相关的事- 这是一种生活方式. 很多好的点子往往是从生活中来的.

Lesson #5-Have/get a life(享受生活)
这可能是最重要的. 年青的爱好者看起来像编码的神(指他们精力充沛),但是火可以快速烧尽. 如果没有适当的休息和意志,你不可能长期从事此职业. 在做好本职工作的情况下尽量少加班,与项目管理者适当的搞好关系, 可以适当的规划. 睡觉,睡觉,睡觉. 有些时候通宵一两个晚上是必然的, 但要小心因为这容易形成一种模式-你的大脑需要休息. 即使睡眠减少你也不会得到更多. 多与人交往,拥有家庭和朋友可以得到更多的快乐, 你的大脑也需要各样的思考.

Lesson #6-Focus(专注)
同一个时间专注于一个事情(不能丢了大局). 尽可能的避免多工作业. 有些时候,在你的工作环境下,单工作业是不大可能的,多个任务在你的大脑中有同样的权重,如同在并发编程中:任务的切换对大脑也是相当堵塞乏味. 你失去了专注点和灵感,并且需要花很多时间去找回他们.

Lesson #7-Be persistent(坚持)
在失败的时候不要放弃. 不断尝试. 你会在你的错误中学到更多,而不是在你的成功故事里. 假如经历了很多次失败后,可以尝试其他的方式解决问题,这和Lesson 3有点关联. 相信我,在大多数的情况下你花了时间就可以找到正确的方法. 不要害怕或者羞于向别人请教-一个新人看待一个问题如同在做奇迹,而老人则不然.

Lesson #8-Measure(衡量)
衡量你可能衡量的任何事情. 不要只”想着”你的方案是最好的. 不要假设,不要太自我. 哪个色彩方案能够吸引更多的用户注册呢?做一下A/B测试,你就会知道. 人类的判断和预测是不准的. 有时候你会对估计和实际的巨大偏差感到惊奇.

Lesson #9-Don’t focus on code performance(不要专注于代码性能)
大多数的情况下,这是不着边际的. 不要花两天或更多的时间优化一个页面的性能,从加载一次550ms变成500ms. 这是不值得的. 你的用户感受不到这样的差异,而你却浪费了宝贵的时间,你应该接着做下一件事. 事实上代码中有些更为重要的因素如:清晰,简单,优雅.

Lesson #10-Be ready to chop off features(准备好砍掉功能)
有些时候,你肯定无法在指定的时间内完成任务. 那么就要准备作出一些牺牲,根据重要性原则重排你的功能,至少砍掉一个重要功能. 然后你可以重新安排时间,完成剩余的功能. 不要认为做不到. 我们的工作就是这样.

Lesson #11-Have ‘coding standards’(编码规范)
即使你不在一个团队中,也要尽量的保持一致. 虽然编码规范是一个可以并且需要发展的标准列表,然而还是一直要尽量的保持一致. 这可以为你和你的团队节省很多时间.

Lesson #12-Test(测试)
要把测试当然工作和计划的一部分,而不是那些乏味的额外工作. 花一些时间做一些适当的测试. 在多个层测试(如:数据层,商业逻辑层,表现层). 坚持不断的做测试,但更重要的是做单元测试. 很多人从事测试. 手头也有很多测试工具-测试服务器,测试软件,如:RSpec,Cucumber,PhpUnit等等.

Lesson #13-Usability(可用性)
当你在做UI的开发的时候,最重要的原则是保持可用性. 这是困难的,我们都有这样的意识,但是作为一个开发者永远不可能和真实的使用者理解一致. 这是事实,做一些实物模式,设计图展示给更多的人,特别是你的最终用户. 接受批评,这是过程的一部分,而不是对你的羞辱.

Categories: translation Tags: ,

jstack – Stack Trace

October 12th, 2009 No comments

英文地址:
http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html

jstack用来打印给定的jvm的线程的栈信息. 为每个java框架打印class全名,方法名,字节码地址,行号. 假如给定的jvm是运行在64位模式,那么你需要指定-J-d64参数,例如: jmap -J-d64 -heap pid
jstack在windows平台上,只能使用的形式如下:
jstack [-l] pid

jstack的命令形式:
jstack [ option ] pid
jstack [ option ] executable core
jstack [ option ] [server-id@]remote-hostname-or-IP

parameters
options
-F
当’jstack [-l] pid’没有相应的时候强制打印栈信息
-l
长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.
-m
打印java和native c/c++框架的所有栈信息.
-h | -help
打印帮助信息

pid
需要被打印配置信息的java进程id,可以用jps查询.

executable
Java executable from which the core dump was produced.
(可能是产生core dump的java可执行程序)

core
将被打印信息的core dump文件

remote-hostname-or-IP
远程debug服务的主机名或ip

server-id
唯一id,假如一台主机上多个远程debug服务

Categories: translation Tags: ,

jmap – Memory Map

October 12th, 2009 No comments

英文地址:
http://java.sun.com/javase/6/docs/technotes/tools/share/jmap.html

jmap可以打印给定的jvm进程或远程debug服务的共享对象的内存映射图或者详细的heap内存信息. 假如给定的jvm是运行在64位模式,那么你需要指定-J-d64参数,例如: jmap -J-d64 -heap pid
jmap在windows平台上,只能使用的形式如下:
jmap -dump: pid

jmap -histo[:live] pid

jmap的命令如下:
jmap [ option ] pid
jmap [ option ] executable core
jmap [ option ] [server-id@]remote-hostname-or-IP

parameters
options

打印jvm中加载的每个共享对象,起始地址,映射的内存大小,共享对象文件的全路径.
-dump:[live,]format=b,file=
输出jvm的heap内容到文件,并使用hprof二进制形式. live子选项如果指定,那么只输出活的对象到文件.
-finalizerinfo
打印正等待回收的对象的信息
-histo[:live]
打印每个class的实例数量,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 假如live子参数加上后,只统计活的对象数量.
-permstat
打印classload和jvm heap持久层的信息. 包括每个classloader的名字,活跃性,地址,父classloader和加载的class数目. 另外,内部String的数量和占用内存数也会打印出来.
-F
强制.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效.
-h | -help
打印帮助信息
-J
传递参数给jmap启动的jvm.

pid
需要被打印配置信息的java进程id,可以用jps查询.

executable
Java executable from which the core dump was produced.
(可能是产生core dump的java可执行程序)

core
将被打印信息的core dump文件

remote-hostname-or-IP
远程debug服务的主机名或ip

server-id
唯一id,假如一台主机上多个远程debug服务

Categories: translation Tags: ,