嗨,本篇文章來說說 Java 的一個小細節(jié):為什么要將局部變量的作用域最小化?

          明人不說暗話啊。這篇文章的靈感來源于《Effective
          Java》,這本書我買了有好長好長一段時間了,書頁都已經(jīng)泛黃,烙下了時間的痕跡,但我仍然還沒有把這本書讀完。說來慚愧啊。

          為什么呢?總感覺這本書的中文翻譯有點拙劣,讀起來煩悶枯燥。明明感覺作者說得非常有道理,但就是提不起半點興致。

          (說完這句話,總覺得有點對不住這本書的譯者,畢竟吐槽容易,分享難啊。)


          為什么要說這些廢話呢,因為怕大家覺得這是不值一提的細節(jié),但往往細節(jié)決定成敗啊。大家不妨換一種比較輕松的心態(tài)來讀一讀。反正我是不怎么喜歡高談闊論的文章,讀完后往往只能感慨一句:“說得不錯啊”,但也僅此而已。

          好了,來步入正題。
          String?[]?strs?=?{"洛陽","牡丹","甲天下"};
          List<String>?list?=?Arrays.asList(strs);

          Iterator<String>?iterator?=?list.iterator();
          while?(iterator.hasNext())?{
          ????String?s?=?(String)?iterator.next();
          ????System.out.println(s);
          }

          list.add("沉默王二");
          Iterator<String>?iterator1?=?list.iterator();
          while?(iterator.hasNext())?{
          ????String?s?=?(String)?iterator1.next();
          ????System.out.println(s);
          }

          大家用“肉眼”看完上面這段代碼后,會覺得有問題嗎?

          如果不細心的話,好像真的很難發(fā)現(xiàn)“復(fù)制-粘貼”引發(fā)的這個問題:第二個 while 循環(huán)的條件中使用了之前的變量 iterator,而不是它應(yīng)該使用的
          iterator1(粘貼后遺漏了變量的修改)。這個問題將會導(dǎo)致代碼在運行的時候拋出java.lang.UnsupportedOperationException
          的錯誤。

          說句實在話,在敲代碼的這十年來,沒少復(fù)制粘貼,沒少因為粘貼后變量沒有修改徹底,而導(dǎo)致出現(xiàn)了各種意料之外的 bug。

          假如把變量的作用域最小化的話,還真的能夠減少這種因為“復(fù)制-粘貼”而導(dǎo)致出現(xiàn)的錯誤。比如說把 while 循環(huán)改造成 for 循環(huán)。
          for?(Iterator<String>?iterator?=?list.iterator();iterator.hasNext();)?{
          ????String?s?=?(String)?iterator.next();
          ????System.out.println(s);
          }

          list.add("沉默王二");
          for?(Iterator<String>?iterator?=?list.iterator();iterator.hasNext();)?{
          ????String?s?=?(String)?iterator.next();
          ????System.out.println(s);
          }

          第二個 for 循環(huán)使用了和第一個 for 循環(huán)一模一樣的代碼,連 iterator 這個變量也不需要修改了。

          從另一方面來看的話,for 循環(huán)比 while 循環(huán)更簡短,可讀性更好。for 循環(huán)還有另外一種最常用的寫法,示例如下。
          for?(int?i?=?0;?i?<?list.size();?i++)?{
          ????System.out.println(list.get(i));
          }

          但這種寫法仍有改進的地方,因為從字節(jié)碼的角度來看,每次循環(huán)都要調(diào)用一次 size() 方法。
          2:?iload_1
          3:?aload_0
          4:?getfield??????#4??????????????????//?Field?list:Ljava/util/List;
          7:?invokeinterface?#5,??1????????????//?InterfaceMethod?java/util/List.size:()I
          12:?if_icmpge?????40

          15:?getstatic?????#6??????????????????//?Field?java/lang/System.out:Ljava/io/PrintStream;
          18:?aload_0
          19:?getfield??????#4??????????????????//?Field?list:Ljava/util/List;
          22:?iload_1

          23:?invokeinterface?#7,??2????????????//?InterfaceMethod?java/util/List.get:(I)Ljava/lang/Object;
          28:?checkcast?????#8??????????????????//?class?java/lang/String

          31:?invokevirtual?#9??????????????????//?Method?java/io/PrintStream.println:(Ljava/lang/String;)V
          34:?iinc??????????1,?1
          37:?goto??????????2
          40:?return

          size() 方法雖然簡短,但也有消耗啊。都有什么消耗呢?說幾個專業(yè)名詞大家感受一下,比如說:創(chuàng)建棧幀、調(diào)用方法時保護現(xiàn)場、調(diào)用方法完畢后恢復(fù)現(xiàn)場。

          (容許我尷尬一下,在寫這篇文章之前,我一直用的上面這種 for 循環(huán)格式??磥韺懳恼逻€是能夠督促自己進步啊。)

          怎么改進呢,看下面這種寫法(強烈推薦?。?。
          for?(int?i?=?0,?n?=?list.size();?i?<?n;?i++)?{
          ????System.out.println(list.get(i));
          }

          在 for 循環(huán)內(nèi)部聲明兩個變量:i 和 n,n 用來保存 i 的極限值,這樣就減少了 size() 方法的調(diào)用次數(shù)(僅有一次了)。

          再來看一段代碼。
          String?pre_name?=?"沉默";
          String?last_name?=?"王二";

          System.out.println(pre_name);
          System.out.println(last_name);

          上面這段代碼看起來挺規(guī)整的,沒什么問題,對吧?它沒有遵守約定——將局部變量的作用域最小化。

          pre_name 變量的作用域結(jié)束的有點晚;last_name 變量的作用域開始的有點早。假如第一個 System.out.println()
          出錯的話,last_name 的聲明就變得毫無意義了。

          (這只是一個例子,變量的處理方法可能比 System.out.println() 復(fù)雜得多。)

          好的寫法應(yīng)該是下面這樣子。
          String?pre_name?=?"沉默";
          System.out.println(pre_name);

          String?last_name?=?"王二";
          System.out.println(last_name);

          有人可能覺得這不是在吹毛求疵嗎?真不是的,變量就應(yīng)該是在第一次使用它的時候聲明。否則的話,變量的作用域要么開始的太早,要么結(jié)束的太晚。

          好了,這篇文章到此就結(jié)束了,非常的簡短,但講清楚了“為什么要將局部變量的作用域最小化”。

          ?

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點信息
          問題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                国产偷人精品高潮露脸 | 在线国产三级 | 国内精品在线观看视频 | 影音先锋 一区二区三区 | 12—13女人毛片毛片 |