劣质代码的产生原因(2)编程语言知识不足 (续2)

 

3.正则表达式

    a. 白名单

    下列代码是用来进行白名单校验的,即如果输入的文字符合条件的话就返回true,否则返回false。

 1 private static final String[] ENABLED_TEXTS = new String[]{"a", "b", "c", "d", "e"};
 2 
 3 public boolean isEnabled(String input) {
 4     for (String text : ENABLED_TEXTS) {
 5         if (text.equals(input)) {
 6             return true;
 7         }
 8     }
 9     return false;
10 }

    当改成使用正则表达式进行校验的时候,代码变成下面这样:

1 public boolean isEnabled(String input) {
2     return input.matches("a|b|c|d|e");
3 }

 

4.用异常代替错误号

   有一段报名课程的代码:

 1 public String register(int userId, int lessonId) {
 2     int ret = checkUser(userId);
 3     if (ret != 0) {
 4          return "User does not exist.";
 5     }
 6 
 7     ret = checkLesson(lessonId);
 8     if (ret != 0) {
 9          return "Lesson does not exist.";
10     }
11 
12     ret = checkLessonExpire(lessonId);
13     if (ret != 0) {
14          return "Lesson is expired.";
15     }
16 
17     ret = register(userId, lessonId);
18     if (ret != 0) {
19          return "Register failed.";
20     }
21 
22     return "";
23 }

    其中有若干处用到了ret这个变量,ret的值检查代码使得代码变长,而且业务流程代码距离拉开了,变得不容易理解。

1 public void register(int userId, int lessonId) throws BusinessException {
2     checkUser(userId);
3     checkLesson(lessonId);
4     checkExpire(lessonId);
5     registerLesson(userId, lessonId);
6 }

    当把上述方法原来的int类型返回值去掉,改成throws BusinessException。修改之后的代码变得紧凑多了。

5.位运算

    计算机表示数据是采用二进制的,几乎所有的计算机培训课程都从二进制开始,但是当写程序到一定程度之后,却忘记了利用二进制的基本运算来简化代码,加快效率。

    a.奇偶运算

     思路1:常见做法是数字除以2求余数

 1 public class OddEven {
 2 
 3     public boolean isEven(int num) {
 4         return num % 2 == 0;
 5     }
 6     
 7     public static void main(String[] args) {
 8         OddEven instance = new OddEven();
 9         System.out.println("3 is " + (instance.isEven(3)?"Even":"Odd"));
10     }
11 }

   思路2:采用位运算之后,代码变成下面这样:

 1 public class OddEven {
 2 
 3     public boolean isEven(int num) {
 4         return (num & 1) == 0;
 5     }
 6     
 7     public static void main(String[] args) {
 8         OddEven instance = new OddEven();
 9         System.out.println("3 is " + (instance.isEven(3)?"Even":"Odd"));
10         System.out.println("36 is " + (instance.isEven(3)?"Even":"Odd"));
11     }
12 }

进一步,我们来看一个斑马线的例子。
    思路1的做法:

 

 1 import java.awt.Color;
 2 
 3 public class Zembra {
 4 
 5     public Color getZembraColor(int index) {
 6         if (index % 2 ==0) {
 7             return Color.GRAY;
 8         } else {
 9             return Color.WHITE;
10         }
11     }
12     
13     public static void main(String[] args) {
14         Zembra zembra = new Zembra();
15         System.out.println(zembra.getZembraColor(23).toString());
16     }
17 }


思路2的做法:

 1 import java.awt.Color;
 2 
 3 public class Zembra {
 4 
 5     public Color getZembraColor(int index) {
 6         Color[] colors = new Color[]{Color.GRAY, Color.WHITE};
 7         return colors[index & 1];
 8     }
 9     
10     public static void main(String[] args) {
11         Zembra zembra = new Zembra();
12         System.out.println(zembra.getZembraColor(23).toString());
13     }
14 }

代码行数比思路1短了,并且,代码的执行效率提高了。但是易懂性有所降低。

 b. Bit Mask

  有些时候我们需要有多种不同层级的属性来表征事物的属性,或者对于同一事物的多种可以并存的属性。

  比如:字体的下划线、粗体、斜体。

  如果采用若干个变量来定义各种属性则每种属性都要设立一个变量。随着可以扩展的属性越来越多,所需要的变量也越来越多,将降低代码的可读性,可理解性。

  为了防止这种属性扩大引起的变量增多的麻烦,以及为未来可能的扩展留有余地,可以采用Bit Mask。

  比如:字体来说每一位(bit)表示一种属性。例如从最后一位开始向左,依次为:下划线、粗体、斜体、删除线、双删除线、上标、下标...

   那么想要知道某一位是否被设置可以通过位运算来获取。

   例如:Font.style来定义那么,计算是否为粗体,那么下列算式用来计算。

   Font.style & 2 == 2

   同样,该技术被应用于窗口属性、文本框语种限制等处。

 c. 四则运算

  当需要计算一个中间值的时候,采用的是(a + b) / 2的形式,但是这个算法有一个Bug,当a+b > Integer.Max的时候,会将计算结果变成负数。

  正确的形式应该是 (a + b) >>> 1;

  具体可以参照Java的二分法Bug报告:

     http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5045582

posted @ 2012-10-27 16:41  史蒂芬.王  阅读(317)  评论(0编辑  收藏  举报