<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          千萬不要再這樣創(chuàng)建集合了!極容易內(nèi)存泄露!

          共 9068字,需瀏覽 19分鐘

           ·

          2021-09-30 12:53



          由于Java語言的集合框架中(collections, 如list, map, set等)沒有提供任何簡便的語法結(jié)構(gòu),這使得在建立常量集合時的工作非常繁索。每次建立時我們都要做:
          1、定義一個空的集合類變量 
          2、向這個結(jié)合類中逐一添加元素 
          3、將集合做為參數(shù)傳遞給方法
          例如,要將一個Set變量傳給一個方法:
          Set users = new HashSet();

          users.add("Hollis");

          users.add("hollis");

          users.add("HollisChuang");

          users.add("hollis666");

          transferUsers(users);

          這樣的寫法稍微有些復(fù)雜,有沒有簡潔的方式呢?




          雙括號語法初始化集合


          其實有一個比較簡潔的方式,那就是雙括號語法double-brace syntax)建立并初始化一個新的集合:

              public class DoubleBraceTest {

                  public static void main(String[] args) {

                      Set users = new HashSet() {{

                          add("Hollis");

                          add("hollis");

                          add("HollisChuang");

                          add("hollis666");

                      }};

                  }

              }

          同理,創(chuàng)建并初始化一個HashMap的語法如下:

              Map<String,String> users = new HashMap<>() {{

                  put("Hollis","Hollis");

                  put("hollis","hollis");

                  put("HollisChuang","HollisChuang");

              }};

          不只是Set、Map,jdk中的集合類都可以用這種方式創(chuàng)建并初始化。

          當(dāng)我們使用這種雙括號語法初始化集合類的時候,在對Java文件進(jìn)行編譯時,可以發(fā)現(xiàn)一個奇怪的現(xiàn)象,使用javac對DoubleBraceTest進(jìn)行編譯:

          javac DoubleBraceTest.java

          我們會發(fā)現(xiàn),得到兩個class文件:

          DoubleBraceTest.class

          DoubleBraceTest$1.class

          有經(jīng)驗的朋友可能一看到這兩個文件就會知道,這里面一定用到了匿名內(nèi)部類。

          沒錯,使用這個雙括號初始化的效果是創(chuàng)建匿名內(nèi)部類。創(chuàng)建的類有一個隱式的this指針指向外部類。



          不建議使用這種形式
          首先,使用這種形式創(chuàng)建并初始化集合會導(dǎo)致很多內(nèi)部類被創(chuàng)建。因為每次使用雙大括號初始化時,都會生成一個新類。如這個例子:

              Map hollis = new HashMap(){{

                  put("firstName", "Hollis");

                  put("lastName", "Chuang");

                  put("contacts", new HashMap(){{

                      put("0", new HashMap(){{

                          put("blogs", "http://www.hollischuang.com");

                      }});

                      put("1"new HashMap(){{

                          put("wechat", "hollischuang");

                      }});

                  }});

              }};

          這會使得很多內(nèi)部類被創(chuàng)建出來:

              DoubleBraceTest$1$1$1.class

              DoubleBraceTest$1$1$2.class

              DoubleBraceTest$1$1.class

              DoubleBraceTest$1.class

              DoubleBraceTest.class

          這些內(nèi)部類被創(chuàng)建出來,是需要被類加載器加載的,這就帶來了一些額外的開銷。

          如果您使用上面的代碼在一個方法中創(chuàng)建并初始化一個map,并從方法返回該map,那么該方法的調(diào)用者可能會毫不知情地持有一個無法進(jìn)行垃圾收集的資源。

              public Map getMap() {

                  Map hollis = new HashMap(){{

                      put("firstName", "Hollis");

                      put("lastName", "Chuang");

                      put("contacts", new HashMap(){{

                          put("0", new HashMap(){{

                              put("blogs", "http://www.hollischuang.com");

                          }});

                          put("1"new HashMap(){{

                              put("wechat", "hollischuang");

                          }});

                      }});

                  }};

                  return hollis;

              }

          我們嘗試通過調(diào)用getMap得到這樣一個通過雙括號初始化出來的map

              public class DoubleBraceTest {

                  public static void main(String[] args) {

                      DoubleBraceTest doubleBraceTest = new DoubleBraceTest();

                      Map map = doubleBraceTest.getMap();

                  }

              }

          返回的Map現(xiàn)在將包含一個對DoubleBraceTest的實例的引用。讀者可以嘗試這通過debug或者以下方式確認(rèn)這一事實。

          Field field = map.getClass().getDeclaredField("this$0");

          field.setAccessible(true);

          System.out.println(field.get(map).getClass());




          替代方案


          很多人使用雙括號初始化集合,主要是因為他比較方便,可以在定義集合的同時對他進(jìn)行初始化。
          但其實,目前已經(jīng)有很多方案可以做這個事情了,不需要再使用這種存在風(fēng)險的方案。

          使用Arrays工具類

          當(dāng)我們想要初始化一個List的時候,可以借助Arrays類,Arrays中提供了asList可以把一個數(shù)組轉(zhuǎn)換成List:

            List<String> list2 = Arrays.asList("hollis ""Hollis""HollisChuang");

          但是需要注意的是,asList 得到的只是一個 Arrays 的內(nèi)部類,是一個原來數(shù)組的視圖 List,因此如果對它進(jìn)行增刪操作會報錯。

          使用Stream

          Stream是Java中提供的新特性,他可以對傳入流內(nèi)部的元素進(jìn)行篩選、排序、聚合等中間操作(intermediate operate),最后由最終操作(terminal operation)得到前面處理的結(jié)果。
          我們可以借助Stream來初始化集合:java

          List<String> list1 = Stream.of("hollis""Hollis""HollisChuang").collect(Collectors.toList());

          使用第三方工具類

          很多第三方的集合工具類可以實現(xiàn)這個功能,如Guava等:

          ImmutableMap.of("k1""v1""k2""v2");

          ImmutableList.of("a""b""c""d");

          關(guān)于Guava和其中定義的不可變集合,我們后面會再詳細(xì)介紹

          Java 9內(nèi)置方法

          其實在Java 9 中,在List、Map等集合類中已經(jīng)內(nèi)置了初始化的方法,如List中包含了12個重載的of方法,就是來做這個事情的:

              /**

               * Returns an unmodifiable list containing zero elements.

               *

               * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.

               *

               * @param <E> the {@code List}'s element type

               * @return an empty {@code List}

               *

               * @since 9

               */


              static <E> List<E> of() {

                  return ImmutableCollections.emptyList();

              }



              static <E> List<E> of(E e1) {

                  return new ImmutableCollections.List12<>(e1);

              }



              static <E> List<E> of(E... elements) {

                  switch (elements.length) { // implicit null check of elements

                      case 0:

                          return ImmutableCollections.emptyList();

                      case 1:

                          return new ImmutableCollections.List12<>(elements[0]);

                      case 2:

                          return new ImmutableCollections.List12<>(elements[0], elements[1]);

                      default:

                          return new ImmutableCollections.ListN<>(elements);

                  }

              }

          瀏覽 17
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色男人色天堂 | 91左爱在线 | 日本AAAA片毛片免费观蜜桃 | 国产中文字幕第一页 | 亚洲熟妇性ⅩXXX交潮喷 |