我觉得严谨对于每个程序员来说都至关重要,而写出优雅而又高效的代码是我们毕生所求。

前言

可能是处女座的原因,我对代码要求很高,我组内几位开发的代码提交前我都会review一次,两年里,我pass掉了很多不满意的代码片段,有实习生写的,也有多年开发经验的同事写的。今天,突然心血来潮和大家分享一些代码片段,希望能给大家带来一些启发和灵感。

主题

受限于我们定式思维的影响,我们写出的代码,很多情况没有别人提醒,自己很难发现一些不妥的地方。

对map掌握不牢

  1. Student student=new Student("邵磊");
  2. Map<String, Object> map3 = new HashMap<String, Object>();
  3. map3.put("k", "学院");
  4. map3.put("v", student.getCollogeName());
  5. resultlist.add( map3);
  6.  
  7. Map<String, Object> map4 = new HashMap<String, Object>();
  8. map4.put("k", "专业");
  9. map4.put("v", student.getMajorName());
  10. resultlist.add( map4);
  11.  
  12. Map<String, Object> map5 = new HashMap<String, Object>();
  13. map5.put("k", "班级");
  14. map5.put("v", student.getBjmc());
  15. resultlist.add(map5);

上述代码,一看就知道,这位开发很可能刚开始只是用一个map,发现list.add后所有的map都是最后一个。
起初代码大概如下

  1. Student student=new Student("邵磊");
  2. Map<String, Object> map = new HashMap<String, Object>();
  3. map.put("k", "学院");
  4. map.put("v", student.getCollogeName());
  5. resultlist.add( map3);
  6.  
  7. map.put("k", "专业");
  8. map.put("v", student.getMajorName());
  9. resultlist.add( map);

这样的代码会导致map被覆盖,因为key相同导致。
那改为他的代码有什么问题吗?
主要是变量名的问题,比如按这样逻辑,你下次还需要map6,map7,map8吧,这种变量维护几次之后,删除,增加都是不优雅的,不妨改为:

  1. Student student=new Student("邵磊");
  2. Map<String, Object> map = new HashMap<String, Object>();
  3. map.put("k", "学院");
  4. map.put("v", student.getCollogeName());
  5. resultlist.add( map3);
  6.  
  7. map = new HashMap<String, Object>();
  8. map.put("k", "专业");
  9. map.put("v", student.getMajorName());
  10. resultlist.add( map);

这样,每次new 了一个hashmap,就可以省去起名不优雅的问题了。
再想想,觉得map里加k,v两个key键有些不优雅,索性改为实体类。

  1. Student student = new Student("邵磊");
  2. resultlist.add(new MapKV("学院", student.getCollogeName()));
  3. resultlist.add(new MapKV("专业", student.getMajorName()));

而这个MapKV就不用介绍了,只有2个String k v。

对mybatis掌握不牢

  1. public interface QuestionDao {
  2. List < Question > getQuestionList();
  3. }

对应的map文件QuestionMapper.xml

  1. List < Question > questionList = QuestionDao.findBy(params);
  2. if (mexamQuestionList == null) {
  3. //抛异常
  4. }

而mybatis的dao层返回的list不可能为null,即使size()=0只会返回一个new List,所以无需判断list为null

对equals不熟

  1. if (user.get("sl").equals("邵磊")) {
  2. //一大堆代码
  3. }

很多人说,这个错误怎么可能有,如果前面为null会报错,但是,我全局搜索过之前的项目,难免能发现一两个,毕竟有历史遗留问题,实习生问题等。因为我们知道null不能.equals,改为:

  1. if ("邵磊".equals(user.get("sl"))) {
  2. //一大堆代码
  3. }

滥用toString

  1. user.get("sl").toString();

而一旦前面为null就报错,null不能有任何方法。

对return不熟

  1. public String getResult() {
  2. if ("条件") {
  3. //一大堆代码
  4. return "结果";
  5. } else {
  6. //一大堆代码
  7. return "结果";
  8. }
  9. }

既然有return了确定以下代码不走,就可以放心大胆放出来

  1. public String getResult() {
  2. if ("条件") {
  3. //一大堆代码
  4. return "结果";
  5. }
  6. //一大堆代码
  7. return "结果";
  8. }

不会使用continue,break、if过长

比如查找某个list中某个姓名,当查找到了,要及时的break,来节约cpu。

  1. for (int i = 0; i < list.size(); i++) {
  2. if ("邵磊".equals(list.get(i).getName())) {
  3. user = list.get(i);
  4. }
  5. }

改为

  1. for (int i = 0; i < list.size(); i++) {
  2. if ("邵磊".equals(list.get(i).getName())) {
  3. user = list.get(i);
  4. break;
  5. }
  6. }

假设除某个姓名的人,不执行某些操作,代码如下:

  1. for (int i = 0; i < list.size(); i++) {
  2. if ("邵磊".equals(list.get(i).getName())) {
  3. //这里只有2件事。
  4. user = list.get(i);
  5. } else {
  6. //这里做很多事情
  7. }
  8. }

这时,我们可以去掉if,并使用continue

  1. for (int i = 0; i < list.size(); i++) {
  2. if ("邵磊".equals(list.get(i).getName())) {
  3. //这里只有2件事。
  4. user = list.get(i);
  5. continue;
  6. }
  7. //这里做很多事情
  8. }

continue:跳出本次循环继续下一次循环
break: 跳出循环体,继续执行循环外的函数体
return: 跳出整个函数体,函数体后面的部分不再执行

对for循环不熟

  1. if (list.size() == 0) {
  2. for (int i = 0; i < list.size(); i++) {
  3. //做事情
  4. }
  5. }

而我们知道即使list.size()==0也不会影响代码,不如直接

  1. for (int i = 0; i < list.size(); i++) {
  2. //做事情
  3. }

错用try catch

try catch包裹一大块

  1. try {
  2. //这段代码可能异常
  3. //下面代码不会异常
  4. //此处代码不会异常
  5. //此处代码不会异常
  6. } catch(Exception e) {
  7. //报错
  8. }

不如改为

  1. try {
  2. //这段代码可能异常
  3. } catch (Exception e) {
  4. //报错
  5. }
  6. //下面代码不会异常
  7. //此处代码不会异常
  8. //此处代码不会异常

这样可读性更高,更优雅,当然了,也可以使用throws来捕获异常。
try catch写在for循环里

  1. for (int i = 0; i < list.size(); i++) {
  2. try {
  3. //这段代码可能异常
  4. } catch(Exception e) {
  5. //报错
  6. }
  7. //下面代码不会异常
  8. }

我们知道try catch 会把整段代码包裹起来执行,这是需要耗费资源的,频繁的trycatch,除特殊情况,否则可抽取出方法,把方法包裹起来即可。

重复代码片段

比如一个方法,在某个类里,多次调用,而只有部分变量不同,可以抽取出方法及变量,来使代码简洁

不使用case

  1. if(type==1){
  2.  
  3. }else if(type==2){
  4.  
  5. }else if(type==3){
  6.  
  7. }else if(type==4){
  8.  
  9. }
  10. …………

这样写下去会写很长的if,而我们知道使用case也可以解决string匹配问题,在java 8以上,支持case 字符串。

  1. switch(参数) {
  2. case 常量表达式1: break;
  3. case 常量表达式2: break;
  4. ...
  5. default: break;
  6. }

未采用懒加载

  1. String str = "邵磊";
  2. if (i == 1) {
  3. list.add(str);
  4. }

可改为

  1. if (i == 1) {
  2. String str = "邵磊";
  3. list.add(str);
  4. }

不断创建对象引用

  1. for (int i = 1; i <= 100; i++)
  2. {
  3. Object obj = new Object();
  4. //其他代码
  5. }

这样做,只会在内存里开辟很多Object对象的引用,可改为

  1. Object obj = new Object();
  2. for (int i = 1; i <= 100; i++)
  3. {
  4. obj = new Object();
  5. //其他代码
  6. }

总结

我们解决问题,可能有很多种思路,也能写出很多种代码来,但是把代码写的优雅却是一个技术活,当然了,本次先介绍部分,关注度高的话,我继续更新。
最后,我想补充一句,其实我不是处女座,只是别人会这么说我,所以我认了。