【Guava 教學】(2)命名明確的條件檢查
|
【Guava 教學】(1)從避免使用 null 開始 << 前情 有多少次了呢?你總會對傳入的引數作一些檢查,像是某個管理物件的容器,你也許會有個 public void add(List<T> lt) {
if(lt == null) {
throw new IllegalArgumentException("不能傳入 null");
}
if(lt.isEmpty()) {
throw new IllegalArgumentException("List 不能是空");
}
// 繼續辦事...
}
每次都得為了做這類的檢查而撰寫類似程式碼的話,為什麼不把它封裝起來呢?像是寫個 public static void checkArgument(boolean expression, Object errorMessage) {
if(expression) {
throw new IllegalArgumentException(errorMessage.toString());
}
}
那麼你原本的方法就可以修改為: public void add(List<T> lt) {
checkArgument(lt != null, "不能傳入 null");
checkArgument(!lt.isEmpty(), "List 不能是空");
// 繼續辦事...
}
看來不錯,那為什麼不用 在 Guava 中對這類前置檢查的工作,實際上在 public void add(List<T> lt) {
checkNotNull(lt, "不能傳入 null");
checkArgument(!lt.isEmpty(), "List 不能是空");
// 繼續辦事...
}
這就是 Bob 大叔在《Clean Code》中一直強調的概念「有意義的命名(Meaningful Names)」,只要有助於可讀性,流程中某個區塊都可以使用函式並「使用具描述能力的名稱(Use Descriptive Names)」來取代。比方說,如果某個方法要檢查物件內部狀態: public void doSome() {
if(container.size() > 100) {
throw new IllegalStateException("超過負載");
}
// 繼續辦事...
}
那麼可以直接使用 Guava 的 public void doSome() {
checkState(container.size() <= 100, "超過負載");
// 繼續辦事...
}
乍看 把語義清晰納入考量的話,你會怎麼修改這段程式碼呢? public T get(int index) {
if(index < 0) {
throw new IllegalArgumentException("索引不得小於 0");
}
if(index >= container.size()) {
throw new IllegalArgumentException("索引超出範圍");
}
// 繼續辦事...
return ...;
}
用 public T get(int index) {
checkArgument(index >= 0, "索引不得小於 0");
checkArgument(index < container.size(), "索引超出範圍");
// 繼續辦事...
return ...;
}
還不錯!不過如果可以更明確地丟出 public T get(int index) {
checkElementIndex(index, container.size());
// 繼續辦事...
return ...;
}
至於 ...
public static int checkElementIndex(int index, int size) {
return checkElementIndex(index, size, "index");
}
public static int checkElementIndex(
int index, int size, @Nullable String desc) {
// Carefully optimized for execution by hotspot (explanatory comment above)
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
}
return index;
}
private static String badElementIndex(int index, int size, String desc) {
if (index < 0) {
return format("%s (%s) must not be negative", desc, index);
} else if (size < 0) {
throw new IllegalArgumentException("negative size: " + size);
} else { // index >= size
return format("%s (%s) must be less than size (%s)", desc, index, size);
}
}
與 public List<T> slice(int start, int end) {
if(start < 0 || end < start || end > container.size()) {
throw new IllegalArgumentException("索引超出範圍");
}
// 繼續辦事...
return null;
}
那麼就可以使用 Guava 提供的 public List<T> slice(int start, int end) {
checkPositionIndexes(start, end, container.size());
// 繼續辦事...
return null;
}
有時候, |

Java 學習之路





Yuen-Kuei Hsueh
06/13最後的論點似乎與Preconditions初衷有點落差
可以參考下列討論串
https://code.google.com/p/guava-libraries/issues/detail?id=1388
javadoc
https://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/base/Preconditions.html
Yuen-Kuei Hsueh
06/13作者或許可以參考 王建興大師的「程式該自我防禦或盡早面對錯誤? 」一文
https://www.ithome.com.tw/itadm/article.php?c=78765&s=1