zoukankan      html  css  js  c++  java
  • 重构:仔细查看,改进代码

    本文由 ImportNew - 陈 晨 翻译自 Java Code Geeks。如需转载本文,请先参见文章末尾处的转载要求。

    我建议你进行一个练习:当你第二天早晨开始工作的时候,重新审视你的项目源码,尝试发现进行重构的机会。就算你的领导没有要求,仍然去做。因为在工作中,你希望有一些激动人心的时候。

    重构是一门改变已经正常的工作的艺术。但是重构是需要理由的。可能是设计改进,性能问题,安全角色或者很多其他的原因。改进程序的技术缺点是要冒风险的,尽管能够使其更稳定,并且可能能够提高你自己今后的生产力。

    这不是为了公司或者领导好,而是为了自己。为什么?因为问题都是逐渐累积的,到达一个程度之后,你会失去对代码的控制。你将会面对苦于交付结果的境地,最终可能毁掉你的职业生涯。

    好吧,让我们从一个更加积极的角度来看这个问题。在重构过程中你会学习到很多,并且很快意识到你产出了比之前更好的代码。重构越多,你就越聪明,慢慢累积直到你达到创新的级别。但是这意味着什么,你又如何知道你达到了呢?

    当你发现一个明显的机会来对你当前的工作进行改进,并且你意识到至今为止还没有别人做过这样的事情(至少你找不到)。这不容易,这不容易,但这常发生在你不断重复做一件事情,并且你能够发现你如何能够使得同样的事情做得又快又好。让我用一个真实的故事来说明。

    例子是在Java中进行字符串连接:一个经典问题,曾经在过去数年困扰了大量专家,但在今天可能已经被忽略了。在JDK1.5之前,尽管可读性高而且简单,但使用“+”来进行字符串连接可能产生效率极低的代码。之后,“+”操作符被换成了StringBuffer,从而真正改进了连接。使用“+”越多,则在内存中的String和StringBuffer实例越多,为了管理所有的对象花费的时间也越多。因此,开发者们被推动使用StringBuffer而忽略“+”。看下面的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    String title = "Mr.";
     
    String name = "John";
     
    String familyName = "Smith";
     
    String message = "Dear " + title + " " +
     
                     name + " " + familyName + ",";

    开发者习惯于这样写代码,但是现在被推动这么做:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    StringBuffer sb = newStringBuffer();
     
    sb.append("Dear ");
     
    sb.append(title);
     
    sb.append(" ");
     
    sb.append(name);
     
    sb.append(" ");
     
    sb.append(familyName);
     
    sb.append(",");

    你可能同意第一个例子可读性高于第二个。开发者使用“+”进行字符串连接时很自然的,所以丢弃这样的形式不合适。好消息是,编译人员做了一些事情来维护这样的习惯,确保了JDK1.5会优化连接方法。代替线程安全的StringBuffer,他们建立了一个叫做StringBuilder(非线程安全,但更快)的类,并且他们确保能够像第一个例子中那样,使用一个实例就能处理所有的连接。这是一个很重要的进步,因为他们兼顾了简洁而不单纯是技术性。第一个例子在编译时会自动转换成如下情况:

     

    1
    2
    3
    4
    5
    6
    7
    StringBuilder sb = newStringBuilder();
     
    sb.append("Dear ").append(title).append(" ")
     
      .append(name).append(" ").append(familyName)
     
      .append(",");

     

    但是,在一些复杂逻辑代码中的字符串连接还是需要使用StringBuilder,因为编译器还没有那么智能,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    List<Student> students = studentBean.findStudents();
     
    String intro = "The following students were approved: ";
     
    String listedNames = "";
     
    String separator = "";
     
    for(Student student: students) {
     
      if(student.approved()) {
     
        if(!listedNames.isEmpty()) {
     
          separator = ", ";
     
        }
     
        listedNames += separator + student.getName();
     
      }
     
    }
     
    String msg = intro + listedNames;
     
    messengerBean.sendMessage(msg);

     

    如下写法会更有效率:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    List<Student> students = studentBean.findStudents();
     
    String intro = "The following students were approved: ";
     
    StringBuilder listedNames = newStringBuilder();
     
    String separator = "";
     
    for(Student student: students) {
     
      if(student.approved()) {
     
        if(!listedNames.length() > 0) {
     
          separator = ", ";
     
        }
     
        listedNames.append(separator)
     
                   .append(student.getName());
     
      }
     
    }
     
    String msg = intro + listedNames.toString();
     
    messengerBean.sendMessage(msg);

    呃!你注意到有什么奇怪的东西了么?可能一眼看起来不是很明显,但是看看他们是如何在定义分隔符之前检查listedNames是否为空的。String类在JDK1.6中有一个可读性很好的方法isEmpty(),但是StringBuilder仍然使用相对比较老的方式。为什么他们不将StringBuilder 和 StringBuffer改为同样的方式呢?

    在核心库开发的邮件列表中讨论了这个问题,没有发现什么明显原因导致他们之前没有这么做。可能只是忘记了。要感谢大规模的重构,试图改进效率低下的字符串连接方法,才能发现这样的不一致。我相信在明年推出的Java8中会有时间修复这个问题。只要在接口CharSequence加入isEmpty()方法,这样就能使得所有实现都变得同样优雅。

     

    这可能是一件简单的事情,但是Java是一个严格审查下的复杂的语言,所以每个细节都会带来很大的影响。所以,做一些重构,发现一些改进代码的机会,同样也能够改进你使用的编程语言。让我们一起推动Java进步吧!

     原文链接: Java Code Geeks 翻译: ImportNew.com 陈 晨
    译文链接: http://www.importnew.com/4827.html

  • 相关阅读:
    使用MobaXterm远程连接Ubuntu,启动Octave,界面不能正常显示
    ABP .Net Core 日志组件集成使用NLog
    ABP .Net Core Entity Framework迁移使用MySql数据库
    ABP前端使用阿里云angular2 UI框架NG-ZORRO分享
    阿里云 Angular 2 UI框架 NG-ZORRO介绍
    Visual Studio 2019 Window Form 本地打包发布猫腻
    VS Code + NWJS(Node-Webkit)0.14.7 + SQLite3 + Angular6 构建跨平台桌面应用
    ABP .Net Core 调用异步方法抛异常A second operation started on this context before a previous asynchronous operation completed
    ABP .Net Core To Json序列化配置
    .Net EF Core数据库使用SQL server 2008 R2分页报错How to avoid the “Incorrect syntax near 'OFFSET'. Invalid usage of the option NEXT in the FETCH statement.”
  • 原文地址:https://www.cnblogs.com/daichangya/p/12958976.html
Copyright © 2011-2022 走看看