读源码时的思考

最近在看concurrent包下线程池的源码,当我看到ThreadPoolExecutor类的时候,发现了JDK源码的一个问题。以下是ThreadPoolExecutor类的addWorker方法的代码片段:

boolean workerStarted = false; boolean workerAdded = false; Worker w = null; try {     w = new Worker(firstTask);     final Thread t = w.thread;     if (t != null) {         final ReentrantLock mainLock = this.mainLock;         mainLock.lock();         try {             int rs = runStateOf(ctl.get());              if (rs < SHUTDOWN ||                 (rs == SHUTDOWN && firstTask == null)) {                 if (t.isAlive()) // precheck that t is startable                     throw new IllegalThreadStateException();                 workers.add(w);                 int s = workers.size();                 if (s > largestPoolSize)                     largestPoolSize = s;                 workerAdded = true;             }         } finally {             mainLock.unlock();         }         if (workerAdded) {             t.start();             workerStarted = true;         }     } } finally {     if (! workerStarted)         addWorkerFailed(w); } return workerStarted;

这段代码的功能是完全没有问题的,但是如果使用卫语句,代码的可读性就会更高了。那么什么是卫语句呢?

 

什么是卫语句?

条件表达式通常有两种表现形式,第一种形式是:所有分支都属于正常行为;第二种形式则是:条件表达式提供的答案中只有一种是正常行为,其他都是不常见的情况。这两类条件表达式有不同的用途,这一点应该通过代码表现出来。

如果两条分支都是正常行为,就应该使用形如if...else...的条件表达式;如果某个条件极其罕见,就应该单独检查该条件,并在该条件为真时立刻从函数中返回。这样的单独检查常常被称为“卫语句”(guard clauses)。只看概念干巴巴的,不好理解,我们来举两个例子。

 

条件检查替换

这是一个计算员工薪资的方法,其中以特殊规则处理驻外员工和退休员工的薪资。这些情况不常有,但的确会偶尔出现。

public double getSalary() {     double result;     if (this.isSeparated) {//驻外员工         result = this.separatedSalary();     } else {         if (this.isRetired) {//退休员工             result = this.retiredSalary();         } else {//正常员工             result = this.normalSalary();         }     }     return result; }

这段代码中,非正常情况的检查掩盖了正常情况的检查,所以应该用卫语句来取代这些条件检查,以提高程序清晰度。对于每个检查,放进一个卫语句。卫语句要不就从函数中返回,要不就抛出一个异常。

 public double getSalary() {     if (this.isSeparated) {//卫语句         return this.separatedSalary();     }     if (this.isRetired) {//卫语句         return this.retiredSalary();     }     return this.normalSalary(); }

 

反转条件替换

这是一个已知长宽高求长方体体积的方法,但有个特殊的需求:高大于0时,打印万猫学社。(惊不惊喜?意不意外?突不突兀?变不变态?是的,有时候我们接到的需求就是这样的。)代码是这样的:

public double getVolume(double length, double width, double height) {     double result = 0.0;     if (height > 0.0) {         System.out.println("万猫学社");         if (length > 0.0 && width > 0.0) {             result = length * width * height;         }     }