Robert Martin曾說過"在代碼閱讀中說髒話的頻率是衡量代碼質量額惟一標準"。同時,代碼的寫法應當使別人理解它所需的時間最小化,也就是說咱們寫的代碼是給人看的而不是給機器看的。那麼,如何編寫優雅代碼呢?能夠從思想層面和具體技巧層面來優化代碼,思想層面指的是遵循面向對象設計原則,本期介紹的是具體技巧。算法
##1. 代碼老是越短越好嗎?bash
assert((!(bucket = findBucket(key))) || !bucket.isOccupied());
複製代碼
上面這行代碼雖然比較短,可是難以閱讀。爲了更好地閱讀,咱們作以下修改:服務器
bucket = findBucket(key);
if(bucket != null){
assert(!bucket.isOccupied());
}
複製代碼
減小代碼行數是一個好目標,可是讓閱讀代碼的事件最小化是個更好的目標。微信
// Fast version of "hash = (65599*hash) + c"
hash = (hash << 6) + (hash << 16) - hash + c
複製代碼
上面這行代碼若是沒有添加註釋,咱們根本不知道是什麼意思,可是有了這行註釋,咱們就知道經過移位操做來提高性能。函數
## 3. tmp的使用 tmp是咱們常常用的,譬如說兩個變量置換,都已變成約定俗成了。性能
tmp = right;
right = left;
left = tmp;
複製代碼
String tmp = user.getName();
tmp += " " + user.getPhoneNumber();
tmp += " " + user.getEmail();
template.set("user_info",tmp);
複製代碼
i,j,k,iter,it
:只用作索引或者循環迭代i,j,k,iter,it
被用作索引或者循環迭代已成爲業界規範了(i是index的縮寫),例如:優化
for(int i=0;i<100;i++){
for(int j=0;j<100;j++){
......
}
}
Iterator<String> iter = list.iterator();
while(iter.hasNext()){
......
}
複製代碼
若是咱們在其餘地方使用i,j,k,那麼就會增長閱讀者的時間。ui
咱們把命名當作一種註釋的方式,讓它承載更多的信息! this
if(debug){
Map<String,Integer> m = new HashMap<>();
lookUpNamesNumbers(m);
print(m);
}
複製代碼
results = Database.all_objects.filter("year<=2011")
複製代碼
上面這行代碼結果如今包含哪些信息?filter是把年份小於等於2011年的數據過濾掉?仍是保留?spa
MAX_ITEMS_IN_CART = 10;
if (shoppingCart.numOfItems()> MAX_ITEMS_IN_CART){
error("Too many items in cart");
}
複製代碼
String s = "Hello world";
s.substring(2,5);-> "llo"
複製代碼
通常來講,getter方法就是獲取一個字段的值,用戶期待的是輕量級的方法,若是你要是在其中作了太多的計算,就應該考慮更名。
public double getMeanPrice(){
//遍歷全部條目計算總價,而後計算平均價格
}
public double computeMeanPrice(){
//遍歷全部條目計算總價,而後計算平均價格
}
複製代碼
public class Account {
// Constructor
public Account(){
}
// Set the profit member to a new value
void setProfit(double profit){
…….
}
// Return the profit from this Account
double getProfit(){
….
}
};
複製代碼
// Releases the handle for this key.This doesn't modify the actual registry. void deleteRegistry(RegistryKey key) 複製代碼
乍一看咱們會誤認爲這是一個刪除註冊表的函數,但是註釋裏澄清它不就改動真正的註冊表。所以,咱們能夠用一個更加自我說明的名字,例如:
void releaseRegistryHandle(registryKey key);
複製代碼
// TODO:採用更快算法或者當代碼沒有完成時 // TODO(dustin):處理除JPEG之外的圖像格式
// users thought 0.72 gave the best size/quality tradeoff
image_quality = 0.72;
// as long as it's >= 2*num_processors,that's good enough
NUM_THREADS = 8;
// impose a reasonable limit - no human can read that much anywhere
const int MAX_RSS_SUBSCRIPTIONS = 1000;
複製代碼
struct Recoder {
vector<float> data;
......
void clear(){
// 每一個人讀到這裏都會問,爲啥不直接調用data.clear()
vector<float>().swap(data);
}
}
複製代碼
若是有一個好的註釋能夠解答讀者的疑問,將上述進行以下修改:強制Vector真正地把內存歸還給內存分配器,詳情請查閱STL swap trick。
void sendMail(String to,String subject,String body);
複製代碼
這個函數因爲須要調用外部服務器發送郵件,可能會很耗時,有可能致使使用者的線程掛起。須要將這段描述放到註釋中。
if ( request.getParameterValue("name")).equals("Brandon"))
,此時將常量"Brandon"能夠避免出現空指針的狀況(上行的參數沒有name或者值爲空)。
if/else書寫規範:首先處理正邏輯而不是負邏輯,例如 if(ok),而不是if(!ok);其次處理掉簡單的狀況,這有利於讓if和else處理代碼在同一個屏幕內可見。
使用提早返回的機制,能夠把函數的嵌套層級變淺。舉個栗子,沒有使用提早返回的代碼:
static bool checkUserAuthority()
{
bool a, b, c, d, e;
if (a)
{
if (b)
{
if (c)
{
if (d)
{
if (e)
{
return true;
}
}
}
}
}
return false;
}
複製代碼
使用了提早返回的代碼:
static bool checkUserAuthority()
{
bool a, b, c, d, e;
if (!a)
return false;
if (!b)
return false;
if (!c)
return false;
if (!d)
return false;
if (!e)
return false;
return true;
}
複製代碼
##20. 經過 "總結變量" 增長可讀性
if(request.user.id == document.owner_id){
// user can edit this document ...
}
if(request.user.id != document.owner_id){
// document is read-only...
}
複製代碼
經過觀察,咱們提取一個變量final boolean user_owns_document=(request.user.id == document.owner_id)
,接着代碼就能夠修改爲:
if(user_owns_document){
// user can edit this document ...
}
if(!user_owns_document){
// document is read-only...
}
複製代碼
在while、for等循環語句中,咱們一般使用自定義的bool變量,來控制流轉。
boolean done = false;
while(/* condition */ && !done){
...
if(...){
done = true;
continue;
}
}
複製代碼
以咱們的經驗,"控制流變量" 能夠經過優化程序結構、邏輯來消除。
while(/* condition */){
...
if(...){
break;
}
}
複製代碼
void foo(){
int i = 7;
if(someCondition){
// i is used only within this block
}
}
void foo(){
if(someCondition){
int i = 7;
// i is used only within this block
}
}
複製代碼
public class LargeClass{
String s;
void method1(){
s = ...
method2();
}
void method2(){
//使用s
}
}
複製代碼
經過參數傳遞來實現數據共享
public class LargeClass{
void method1(){
String s = ...
method2(s);
}
void method2(String s){
//使用s
}
}
複製代碼
把全部變量定義在開頭是C語言的風格,面嚮對象語言習慣將變量定義在離它開始使用的地方。
public void foo(){
boolean debug = false;
String[] pvs;
String pn;
String pv;
...
}
複製代碼
除了上述建議以外,咱們還能夠參考阿里Java規範,關注微信號:"木可大大",發送"阿里Java規範"便可得到相關資料。
歡迎關注微信公衆號:木可大大,全部文章都將同步在公衆號上。