Java編程常見"坑"匯總(下)
30.對List的誤用
建議下列情境用Array來替代List:
1.list長度固定,比如一周中的每一天
2.對list頻繁的遍曆,比如超過1w次
3.需要對數字進行封裝(主要JDK沒有提供基本類型的List)
比如下面的代碼。
錯誤的寫法:
List<Integer> codes = new ArrayList<Integer>();
codes.add(Integer.valueOf(10));
codes.add(Integer.valueOf(20));
codes.add(Integer.valueOf(30));
codes.add(Integer.valueOf(40));
正確的寫法:
int[] codes = { 10, 20, 30, 40 };
錯誤的寫法:
// horribly slow and a memory waster if l has a few thousand elements (try it yourself!)
List<Mergeable> l = ...;
for (int i=0; i < l.size()-1; i++) {
Mergeable one = l.get(i);
Iterator<Mergeable> j = l.iterator(i+1); // memory allocation!
while (j.hasNext()) {
Mergeable other = l.next();
if (one.canMergeWith(other)) {
one.merge(other);
other.remove();
}
}
}
正確的寫法:
// quite fast and no memory allocation
Mergeable[] l = ...;
for (int i=0; i < l.length-1; i++) {
Mergeable one = l[i];
for (int j=i+1; j < l.length; j++) {
Mergeable other = l[j];
if (one.canMergeWith(other)) {
one.merge(other);
l[j] = null;
}
}
}
實際上Sun也意識到這一點, 因此在JDK中, Collections.sort()就是將一個List拷貝到一個數組中然後調用Arrays.sort方法來執行排序。 31.用數組來描述一個結構
錯誤用法:
/**
* @returns [1]: Location, [2]: Customer, [3]: Incident
*/
Object[] getDetails(int id) {...
這裡用數組+文檔的方式來描述一個方法的傳回值. 雖然很簡單, 但是很容易誤用, 正確的做法應該是定義個類。
正確的寫法:
Details getDetails(int id) {...}
private class Details {
public Location location;
public Customer customer;
public Incident incident;
}
32.對方法過度限制
錯誤用法:
public void notify(Person p) {
...
sendMail(p.getName(), p.getFirstName(), p.getEmail());
...
}
class PhoneBook {
String lookup(String employeeId) {
Employee emp = ...
return emp.getPhone();
}
}
第一個例子是對方法參數做了過多的限制, 第二個例子對方法的傳回值做了太多的限制。
正確的寫法:
public void notify(Person p) {
...
sendMail(p);
...
}
class EmployeeDirectory {
Employee lookup(String employeeId) {
Employee emp = ...
return emp;
}
}
33.對POJO的setter方法畫蛇添足
錯誤的寫法:
private String name;
public void setName(String name) {
this.name = name.trim();
}
public void String getName() {
return this.name;
}
有時候我們很討厭字串首尾出現空格, 所以在setter方法中進行了trim處理, 但是這樣做的結果帶來的副作用會使getter方法的傳回值和setter方法不一致, 如果只是將JavaBean當做一個資料容器, 那麼最好不要包含任何商務邏輯. 而將商務邏輯放到專門的業務層或者控制層中處理。
正確的做法:
person.setName(textInput.getText().trim());
34.SimpleDateFormat非安全執行緒誤用
錯誤的寫法:
public class Constants {
public static final SimpleDateFormat date = new SimpleDateFormat("dd.MM.yyyy");
}
SimpleDateFormat不是安全執行緒的. 在同步多執行緒的情況下, 會得到非預期的值. 這個錯誤非常普遍! 如果真要在多線程環境下公用同一個SimpleDateFormat, 那麼做好做好同步(cache flush, lock contention), 但是這樣會搞得更複雜, 還不如直接new一個實在。
35.使用全域參數配置常量類/介面
public interface Constants {
String version = "1.0";
String dateFormat = "dd.MM.yyyy";
String configFile = ".apprc";
int maxNameLength = 32;
String someQuery = "SELECT * FROM ...";
}
很多應用都會定義這樣一個全域常量類或介面, 但是為什麼這種做法不推薦? 因為這些常量之間基本沒有任何關聯, 只是因為公用才定義在一起. 但是如果其他組件需要使用這些全域變數, 則必須對該常量類產生依賴, 特別是存在server和遠程client調用的情境。