這是一篇結合項目代碼與《編寫可讀藝術的代碼》一書結合的讀書筆記
代碼應當易于理解
《編寫可讀藝術的代碼》這本書告訴我們代碼應該寫的容易理解,我更喜歡作者的另一個說法是使別人用最短的時間理解你的代碼
不知道大家有沒有想過,什么樣的代碼是好的,當我們忙于業(yè)務開發(fā)的時候可以停下來思考一下這個問題?當我看到這個問題的時候,腦海中的第一個想法就是肯定是將代碼寫的越少越好。
Part 1 表面層次的改進
把信息裝到名字里
選擇直接的名字,寫簡單明了的注釋,把代碼寫的整潔,格式更好,說白了就是讓他人僅通過類名,方法名以及變量名,就可以知道他們的作用,或者說大概能了解它們的作用,這要求我們起的名字的含義要足夠清晰,明確,不能太過于含糊。
一、使用專業(yè),明確,具體的名字,避免使用模糊,抽象,具有二義性的名字
通常我們會定義 getXXX() 方法名,表示表獲取數(shù)據(jù),get 這個名字并沒有表達出更多的信息,你并不知道是從網(wǎng)絡上獲取或者是數(shù)據(jù)庫上,又或者是從緩存中獲取數(shù)據(jù),可以考慮用 fetch,download,find,search 等含義更明確,更形象的單詞替代。
1、getXxx() --> findXxx()
我個人對于 get 的理解是得到一個數(shù)據(jù),這個數(shù)據(jù)應該是一個類的簡單屬性,不用經(jīng)過復雜的計算,例如 JavaBean 的 get 操作。
Picasso.with(this).load(info.getIvArrearsReasonImageRes()).into(imgArrear);
//通過該方法獲取一個圖片資源,然后交由 Picasso 幫我們加載
info.getIvArrearsReasonImageRes();
初看這個方法我會以為這個圖片資源是 info 對象的一個屬性,以下是這個方法的全部內(nèi)容:
public int getIvArrearsReasonImageRes() {
if (type == 1) {
return R.drawable.debt_1;
} else if (type == 2) {
return R.drawable.debt_2;
} else if (type == 3) {
return R.drawable.debt_3;
} else if (type == 5) {
return R.drawable.debt_5;
} else if (type == 7) {
return R.drawable.debt_7;
} else if (type == 9) {
return R.drawable.debt_9;
} else if (type == 20) {
return R.drawable.debt_20;
} else {
return R.drawable.debt_other;
}
}
這個方法會根據(jù) info 對象中的 int 類型的屬性 type 值 來判斷應該返回哪個圖片資源文件,所以我將方法名更改為 findArrearsReasonImageRes(),這樣你可能在看到這個方法時候會有一個預期。(內(nèi)心PS:我只要知道 get 一個圖片資源就好了,誰管你內(nèi)部是怎么返回給我。)
再來看看下面一個方法
private int getCurSmsId() {
if (smsList != null && !ListUtils.isEmpty(smsList.getSmsList())) {
for (SmsTemplateItem item : smsList.getSmsList()) {
if (item.isSelected) {
return item.id;
}
}
}
return -1;
}
這個方法是用來獲取當前選中短信模板的ID,也是很普通的循環(huán)查找,我更愿意把它命名為 findSelectedId(),之所以沒有加上模板這個單詞是因為這個方法本身就是被短信模板業(yè)務對象所調用。
2、orders() --> parseOrders() 或者 parseOrderArray()
toDetailPage(assign.getTask_Id(), assign.orders(), isInRefresh ? POSITION_REFRESH : POSITION_MY_TASK);
這個方法接收三個參數(shù),其中第二個參數(shù)表示從 assign 對象中獲取 Order 類型的數(shù)組,以下是該方法的全部內(nèi)容:
public List<Order> orders() {
if (!TextUtils.isEmpty(orders)) {
return Json.fromJsons(orders, Order.class);
} else {
return null;
}
}
orders 是一串原始的的 Json 字符串,當它不為空的時候,我們會將它解析成對應類型的數(shù)組并返回,最初在不知道這個內(nèi)部邏輯的情況下,我以為 ordres 是 assign 中的屬性,并且在 assign 的整個生命周期中,我們會對它內(nèi)部持有的 Order 數(shù)組(我以為 Orders 是數(shù)組)進行修改,由于我們只是將 Json 字符串解析成對應的對象類型而已,無論我們對解析后的對象如何操作,都不會對原始 Json 字符串產(chǎn)生任何影響,這個方法給我們造成了不小的麻煩,后來我們將它的名字修改為 parseOrders()/parseOrderArray()
3、distanceBetweenUs() --> computeDistanceBetweenUs()
這個例子也很直白 distanceBetweenUs(),返回我們之間的距離,但是實際上代碼的內(nèi)部是通過地圖 SDK 進行耗時的計算得到的。我想將它改為 computeDistanceBetweenUs() 應該會合適一些,至少看到這個名字,你會思考它會不會耗時。
4、start() 和 stop() --> create() 和 destroy()
public interface Presenter {
void start();
void stop();
//...
}
這個接口表示 MVP 模式中的 P層(Presenter),由于 Presenter 需要和我們的生命周期進行綁定,所以我們會在 P 層中提供對應的生命周期方法,然而上述代碼中的 start() 和 stop() 兩個方法是在 onCreate() 和 onDestroy() 方法中被調用的,這很可能會產(chǎn)生誤解,因此我將它們改成了 onCreate() 和 onDestroy()
二、避免空泛的名字
1、temp
private static SpannableString getRMBSpannableString(double rmb, String color, String typefaceSpan) {
if (rmb <= 0)
return null;
String temp = "¥" + Strings.priceRoundFloor(rmb);
SpannableString spannableString = new SpannableString(temp);
spannableString.setSpan(new ForegroundColorSpan(Color.parseColor(color)), 0, temp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// new TypefaceSpan("monospace") 保證 ¥ 符號顯示 2橫
spannableString.setSpan(new TypefaceSpan(typefaceSpan), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableString;
}
這個方法是用來獲取一個格式化的人民幣字符串,在代碼中間出現(xiàn)了兩個變量 temp 和 spannableString 沒有具體的含義,我選擇這兩個變量名的原因是因為我的懶惰,完全沒有考慮到可讀性
2、retval
private int getTotalPackageNum() {
int retval = 0;
for (CarloadLuggageItem item : packageListItems) {
retval += item.getPackage_num();
}
return retval;
}
retval 意思是返回值 return value,這段代碼的中心是求和操作,retval 代表包裹的總數(shù)量,我們可以選擇命名為 totalPackageNum 可能會體現(xiàn)出更多的信息
3、循環(huán)迭代器
for (int i = 0; clubs.length; i++) {
for (int j = 0; clubs.[i].members.lenght; j++) {
for (int k = 0; users.length; k++) {
if (clubs[i].members[k] == users[j]){
do something...
}
}
}
}
你可能很難發(fā)現(xiàn) clubs[i].members[k] == users[j] 這段代碼,我們標錯了數(shù)組的下標,如果不使用 i j k 作為數(shù)組的下標而是結合變量名如 if (clubs[ci].members[mj] == users[uk]) 的方式,會更容易發(fā)現(xiàn)問題
4、給變量名加上重要的細節(jié)和特殊的格式
- 超時時間單位: int timeOut -- int timeOutSecs
- 創(chuàng)建時間單位: long createTime -- long createTimeMills
- 原始的 Json 字符串: String orders -- String rawJsonOrders
- 緩存單位: long cacheSize -- cacheMb
- ...
5、抽象的名字
- SmartSerialExecutor: 智能的串行線程池,實際并沒有很智能,也沒有能夠知道這個線程池有什么特色
- BitmapCrop:Bitmap 裁剪,實際上內(nèi)部代碼僅僅是提供一個圓形 Bitmap
- ...
6、作用域大的變量名字更長
- RefreshListOrderItemView.java Method: addOrderItems
- ActivityTaskUnFinished.java Filed: order
三、代碼格式
- 使用一致的布局,讓讀者很快就習慣這種風格
- 讓相似的代碼看上去相似
- 把相關的代碼分組,形成代碼塊
1、有意義的順序
我們都使用過 Dialog,它大概由,標題,副標題,內(nèi)容,確認按鈕,取消按鈕這幾部分組成,我們在自定義 Dialog 的時候可以按照 Dialog 展示的順序來定義屬性:
public static class CustomDialog {
private String title;
private String subTitle;
private String content;
private String negativeButton;
private String positiveButton;
}
如果我們隨意的,無序的定義這些屬性,在屬性很多的情況下使用起來可能會有一些混亂,如果屬性定義的順序和設計稿的順序序一致,在使用起來就很舒暢
2、代碼分段
public void loadPic(ScreenAd ad) {
final String linkUrl = ad.getLink_url();
final int countDown = ad.getCount_down();
String displayUrl = ad.getDisplay_url();
if (TextUtils.isEmpty(displayUrl)) {
return;
}
int screenAdWidth = ad.getWidth();
int screenAdHeight = ad.getHeight();
if (screenAdWidth <= 0 || screenAdHeight <= 0) {
return;
}
initAdUI(screenAdWidth, screenAdHeight);
Picasso.with(getActivity()).load(displayUrl).fit().into(ivA);
}
通過空格對代碼進行分段,這樣每一段都有各自的邏輯處理,如果沒有空格進行分段的話,代碼就會變得不夠清晰。
3、團隊風格
團隊風格很重要,當團隊人數(shù)增加后,如果每個人都按照自己喜愛的風格來編程,整個工程對于他人來說將變得更難理解。比如我們的初始工程中大部分的 Activity 命名方式都是 ActivityBusiness,盡管我習慣于業(yè)務在前的命名方式,但我仍然遵循項目中之前的命名方式。
Part 2 簡化循環(huán)和邏輯
一、使控制流易讀
把條件,循環(huán)以及其他對控制流的改變做的越“自然”越好。運用一種方式使讀者不用停下來重讀你的代碼
控制流語句指代碼中的條件判斷,循環(huán)等語句。大量的復雜的 if,switch, for 循環(huán)等語句會使代碼產(chǎn)生大量的分支,縮進,嵌套,變得混亂。我們的目標是讓這些控制流語句變得容易閱讀,容易理解。
二、條件語句中參數(shù)的順序
按照我們平時口語的表達習慣,一般你會說 “我的身高高于 180 cm” 而不是 “180 cm 沒有我的身高高”,我們習慣將變量放在左側,而將常量放在右側。
final int id = AwsomeDaemonService.getId();
if (Transporter.LOGIN_INFORMATION_LOSS == id) {
Toasts.shortToast(R.string.login_information_loss_prompt);
return;
}
這段代碼的意思,判斷當前用戶的信息是否丟失,如果丟失的話,則 Toast 提示用戶。我們比較語句寫的是 Transporter.LOGIN_INFORMATION_LOSS == id 中文直譯過來就是用戶信息丟失狀態(tài)是當前用戶的狀態(tài),我們在腦海中還需要將它轉換為用戶當前的狀態(tài)是丟失狀態(tài)。
將比較語句改為 if (id == Transporter.LOGIN_INFORMATION_LOSS) 可讀性會更好些。
1、if else 語句塊的順序
- 先處理正邏輯,用
if(debug)而不是if(!debug) - 先處理簡單的情況
- 先處理危險的情況
以上是書中給出的關于 if/else 書寫順序的建議,這些建議之間會有沖突,需要具體情況具體對待。
先處理正邏輯
if (!TextUtils.equals(response.getContent(), "0")) {
vRedPoint.setVisibility(View.VISIBLE);
} else {
vRedPoint.setVisibility(View.GONE);
}
我在項目中找到一些代碼,對于 if/else 代碼塊處理的代碼行數(shù)相差無幾,上面的例子用來控制一個 View 是否需要隱藏,即使先寫負邏輯,也沒有覺得有什么問題。
if (Transporter.get().isSleep()) {
ivEmpty.setImageResource(R.drawable.close_assign_gray);
tipTV.setText("休息一下,勞逸結合");
vGoHotMap.setVisibility(View.GONE);
} else {
ivEmpty.setImageResource(R.drawable.empty_picking_up_order);
tipTV.setText("暫無訂單\n打開地圖,前往訂單多的區(qū)域");
vGoHotMap.setVisibility(View.VISIBLE);
}
根據(jù)騎士的開工收工狀態(tài),來切換一些文案內(nèi)容的顯示,這段代碼是正邏輯,但是即使我將寫成負邏輯,我想也沒有什么關系。
從中文表達邏輯上來說,我們可能更習慣先處理正邏輯在處理負邏輯,但是在它們的代碼塊行數(shù)沒有明顯區(qū)別的時候,我覺得處理順序沒有什么影響
先處理簡單的情況
先處理 if/else 語句塊中簡單的那部分
if (order.supplierDistanceBetweenYou() <= 0) {
tvDistanceBetweenYou.setText("計算中");
order.supplierDistanceBetweenYou(new AddressUtil.WalkDistanceListener() {
@Override
public void onWalkDistanceSearched(int distance) {
if (isDetached())
return;
long orderId = (Long) tvDistanceBetweenYou.getTag();
if (orderId == order.getId()) {
order.setDistanceBetweenYouAndSupplier(distance);
tvDistanceBetweenYou.setText(Strings.formatDistanceWithMax(distance));
mapPresenter.addDistanceTip(distance);
}
}
@Override
public void onSearchFailed() {
if (isDetached() || tvDistanceBetweenYou == null)
return;
long orderId = (Long) tvDistanceBetweenYou.getTag();
if (orderId == order.getId()) {
float[] results = new float[1];
Location.distanceBetween(PhoneInfo.lat, PhoneInfo.lng, order.getSupplier_lat(), order.getSupplier_lng(), results);
float distance = results[0];
order.setDistanceBetweenYouAndSupplier(distance);
tvDistanceBetweenYou.setText(distance == 0 ? "..." : Strings.formatDistanceWithMax(distance));
mapPresenter.addDistanceTip(distance);
}
}
});
} else {
mapPresenter.addDistanceTip(order.supplierDistanceBetweenYou());
}
上面代碼會從 order 信息中獲取一個距離信息,如果距離 <= 0 的話就需要一系列復雜的計算,然而 else 語句塊中的代碼只有一行,很有可能這個時候,我們滿屏都是 if 語句塊中的代碼,很容易忽略掉 else 語句塊的處理,這個時候我們不妨將先處理距離 > 0 的情況,這樣 if/else 的代碼塊都可以在一屏之間看見,處理了簡單的邏輯之后,可以更專注在復雜的邏輯中。
先處理有趣的情況
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
這是 EventBus 解除注冊中的一段代碼,相比較于 else 語句中的打印日志,明顯我們更專注 if 語句中的邏輯。
2、三目運算符
記得在我最開始寫代碼的時候,特別喜歡用三目運算符,只用一行代碼就可以替代原有的 if/else 結構
if/else 結構:
if (conditions){
return XXX;
}else {
return YYY;
}
三目運算符結構:
conditions ? XXX : YYY;
如果實際情況有這么簡單,當然可以寫成三目運算符的情況,然而你很有可能面臨這樣的情況:
height = (height <= availableHeight) ? (width * rawPicHeight / rawPicWidth) : rootHeight - iconHeight;
這段代碼根據(jù)某個條件來計算 height 的值,這里三目運算符已經(jīng)不是從簡單的兩個值中做出選擇,而是為了將所有的代碼擠進一行里,導致可讀性變差。
使用 if/else 格式來改寫上述代碼:
if (height <= availableHeight) {
height = (width * rawPicHeight / rawPicWidth);
} else {
height = rootHeight - iconHeight;
}
相對于追求最小化代碼行數(shù),一個更好的度量方法是最小化理解它所需要的時間
三、最小化嵌套
我們的項目中由于各種各樣的原因,肯定會有一些嵌套很深的代碼,多層嵌套的代碼難以理解,會加深我們的思維棧,每當多處理一層嵌套,我們腦海中的思維棧就加深了一層,因此我們要盡量減少代碼中的嵌套。
if (Transporter.isLogin()) {
//是否需要展示實地培訓的綠色按鈕
if (transporter.canApplyOfflineTraining()) {
ViewUtils.visible(vFieldTraining);
}
if (transporter.isMissionCompleted()) {
ViewUtils.gone(vTiro);
TiroHelper.getInstance().destroyBottomDialog();
} else{
if (isNeedCheckTiroNew) {
//檢測新手體驗單是否展示
TiroHelper.getInstance().checkNewTiroDialogIsShowing(this);
getTransporterDetails();
}
}
} else {
//如果未登陸,直接隱藏收工按鈕
ViewUtils.gone(vAssign);
ViewUtils.gone(vFieldTraining);
ViewUtils.gone(vTiro);
isNeedCheckTiroNew = false;
TiroHelper.getInstance().destroyBottomDialog();
}
這是我從 ActivityMain.java 中抽出并簡化的一段代碼,在最初我們可能只有接單的 if/else 結構
if (Transporter.isLogin()) {
//do something
} else {
//do something
}
后來需求變更要求我們在用戶登錄的情況下,新增一些判斷,我們自然而然的就寫成了多嵌套的形式,我們可以通過提前返回來減少嵌套
if (!Transporter.isLogin()) {
//如果未登陸,直接隱藏收工按鈕
ViewUtils.gone(vAssign);
ViewUtils.gone(vFieldTraining);
ViewUtils.gone(vTiro);
isNeedCheckTiroNew = false;
TiroHelper.getInstance().destroyBottomDialog();
return;
}
//是否需要展示實地培訓的綠色按鈕
if (transporter.canApplyOfflineTraining()) {
ViewUtils.visible(vFieldTraining);
}
if (transporter.isMissionCompleted()) {
ViewUtils.gone(vTiro);
TiroHelper.getInstance().destroyBottomDialog();
return;
}
if (isNeedCheckTiroNew) {
//檢測新手體驗單是否展示
TiroHelper.getInstance().checkNewTiroDialogIsShowing(this);
getTransporterDetails();
}
減少循環(huán)內(nèi)的嵌套
for (CarloadLuggageItem checkItem : result.getDetails()) {
if (!checkItem.isAvailable()) {
for (int i = 0; i < packageListItems.size(); i++) {
CarloadLuggageItem item = packageListItems.get(i);
if (TextUtils.equals(item.getJd_order_no(), checkItem.getJd_order_no())) {
item.setIs_passed(CarloadLuggageItem.UNPASS);
bindFailList.add(new CheckFailItem(item.getJd_order_no(), item.getPackage_num()));
break;
}
}
}
}
這也是之前項目中的代碼,用來更改本地數(shù)據(jù)的成功或者失敗的狀態(tài),我們依然可以通過提前返回來減少一層嵌套:
for (CarloadLuggageItem checkItem : result.getDetails()) {
if (checkItem.isAvailable())
continue;
for (int i = 0; i < packageListItems.size(); i++) {
CarloadLuggageItem item = packageListItems.get(i);
if (TextUtils.equals(item.getJd_order_no(), checkItem.getJd_order_no())) {
item.setIs_passed(CarloadLuggageItem.UNPASS);
bindFailList.add(new CheckFailItem(item.getJd_order_no(),item.getPackage_num()));
break;
}
}
}
- 在寫一個比較的時候,把變量寫在左側,把常量寫在右側更好一些
- 重新排列 if/else 語句中的語句塊,通常來講,先處理正確的/簡單的/有趣的情況
- 三目運算符有可能導致代碼的可讀性變差,可以用更整潔的方式替代它
- 嵌套的代碼塊需要更加集中注意力去理解,盡量將它改寫成線性的代碼
- 可以通過提早返回來減少代碼嵌套,讓代碼變得更整潔
四、拆分超長的表達式
大多數(shù)人腦只能同時思考 3-4 件事情,如果代碼,表達式太長,就會超出大腦思考的并發(fā)數(shù),這樣的代碼就會變得難以理解,因此我們需要將超長的表達式拆分容易理解的小代碼塊
1、解釋變量
我們可以通過額外引入一個變量-解釋變量,讓它來表示一個小一點的子表達式。
if (ListUtils.isEmpty(order.getDisplay_tags())
//標簽不為空
&& TextUtils.isEmpty(order.getOrigin_mark())
&& TextUtils.isEmpty(order.getOrigin_mark_icon())
&& TextUtils.isEmpty(order.getOrigin_mark_no())) {
targetView.setVisibility(View.GONE);
} else {
targetView.setVisibility(View.VISIBLE);
}
if 語句中的條件表達式很長,但是它其實就要表達一個意思,需不需要顯示 Tag,我們可以定義一個解釋變量,用來解釋這個條件表達式
boolean isNeedShowTag = order.getDisplay_tags())
&& TextUtils.isEmpty(order.getOrigin_mark())
&& TextUtils.isEmpty(order.getOrigin_mark_icon())
&& TextUtils.isEmpty(order.getOrigin_mark_no())
if (isNeedShowTag) {
targetView.setVisibility(View.VISIBLE);
} else {
targetView.setVisibility(View.GONE);
}
2、總結變量,重復代碼
即使一個表達式很簡單,你可以直接看出它的含義,也可以把它裝入一個新的變量中-總結變量,用一個很短的名字,來代替一大段代碼,易于理解和思考
if (order.getFetchType() == Order.FETCH_TYPE_FROM_PACKAGE) {
//同城速遞集包取件
getDadaApiV1().fetchCityExpressList(getActivity(), order, id);
}
... 省略
if (order.getFetchType() != Order.FETCH_TYPE_FROM_PACKAGE) {
EventBus.getDefault().post(new ForcePickUpEvent());
}
代碼組要是來判斷該筆訂單是否是同城速遞訂單,然后針對不同的情況進行處理。我們可以通過增加一個總結變量來表達的更清楚。
boolean isSameCityExpress = order.getFetchType() == Order.FETCH_TYPE_FROM_PACKAGE;
if (isSameCityExpress){
do something
}
if (!isSameCityExpress){
do something
}
有的時候,我們的代碼中會有一些重復的代碼,我們也可以將這些重復代碼提取出來,用一個變量來表示
if (order.getOrder_status() == Order.ORDER_STATUS_PICKUP) {
OrderOperation.getInstance().dispatching(getActivity(),order);
} else if (order.getOrder_status() == Order.ORDER_STATUS_DISPATCHING) {
OrderOperation.getInstance().finish(getActivity(), true, order, null,finishCode);
} else if (order.getOrder_status() == Order.ORDER_STATUE_FINISHED){
...
}
order.getOrder_status() 會重復出現(xiàn)多次,它表示獲取訂單的狀態(tài),我們可以定義一個變量來表示它 int orderStatus = order.getOrder_status()
3、短路操作
有的時候我們可以使用短路行為來使代碼變得更簡潔。
例如我們 ListUtils 工具類中的方法。
public static <V> boolean isEmpty(List<V> sourceList) {
return (sourceList == null || sourceList.size() == 0);
}
public static <V> boolean isNotEmpty(List<V> sourceList) {
return (sourceList != null && sourceList.size() > 0);
}
很好的利用短路邏輯,不然你可能需要寫多個 if 語句
public static <V> boolean isEmpty(List<V> sourceList) {
if (sourceList == null) {
return true;
}
if (sourceList.size() == 0) {
return true;
}
return false;
}
五、變量與可讀性
為什么說對變量的草率運用會讓程序變得更難理解?
- 變量越多,就會越難追蹤它們的動向
- 變量的作用域越大,就需要追蹤它的動向越久
1、減少變量
沒有價值的臨時變量,多余的中間變量,我們都可以通過一些方式來消除它。
沒有價值的臨時變量
沒有起到解釋或者總結的作用,并且只用到了一次,一般來說,在定義臨時變量的時候,預計是在之后會使用到它,但實際上沒有使用到它,也沒有將它刪除。
/**
* 獲取訂單卡片的小費
*/
public static double getOrderTips(OrderTaskInfo item) {
Order order = item.getFirstOrder();
double displayOrderTips = order.getTips();
...
}
可以看到我們定義了一個 order 對象,這個 order 對象只用到了一次,沒有什么特殊的價值,我們完全可以移除這個對象 double displayOrderTips = item.getFirstOrder().getTips();
減少中間結果
int selectPosition
for (int i = 0; i < adapter.size(); i++) {
if (adapter.get(i).isSelected()) {
selectPosition = i;
break;
}
}
return adapter.get(selectPosition);
這段代碼是找出數(shù)據(jù)源中的選中項,并且返回它,我們可以通過在循環(huán)體中直接返回選中項,從而消除 selectPosition 這個變量
for (int i = 0; i < adapter.size(); i++) {
Object object = adapter.get(i);
if (object.isSelected()) {
return object;
}
}
2、減小每個變量的作用域
變量的作用域越小越好,盡量將變量移動到一個對其他代碼可見性低的地方。