Java 性能調(diào)優(yōu)指南之 Java 集合概覽

【編者按】本文作者為擁有十年金融軟件開(kāi)發(fā)經(jīng)驗(yàn)的 Mikhail Vorontsov,文章主要概覽了所有標(biāo)準(zhǔn) Java 集合類(lèi)型。文章系國(guó)內(nèi) ITOM 管理平臺(tái) OneAPM 編譯呈現(xiàn),以下為正文:

本文將概覽所有標(biāo)準(zhǔn)的 Java 集合類(lèi)型。我們將按照它們可區(qū)分的屬性與主要用例進(jìn)行分類(lèi)。除此之外,我們還將窮舉在不同集合類(lèi)型之間進(jìn)行數(shù)據(jù)轉(zhuǎn)換的方法。

數(shù)組(Arrays)

數(shù)組是 Java 語(yǔ)言?xún)?nèi)置的唯一集合類(lèi)型,尤其擅長(zhǎng)處理預(yù)先知道數(shù)量上限的元素集。java.util.Arrays 包含了許多用于處理數(shù)組的方法,列舉如下:

  • Arrays.asList ——將 array(數(shù)組) 轉(zhuǎn)變?yōu)?List(列表),后者可以傳值給其他標(biāo)準(zhǔn)的集合構(gòu)造函數(shù)。
  • Arrays.binarySearch ——對(duì)有序數(shù)組或其分段進(jìn)行快速查找。
  • Arrays.copyOf ——如果想在擴(kuò)展數(shù)組的同時(shí)保存其內(nèi)容,可調(diào)用該方法。
  • Arrays.copyOfRange ——如果需要拷貝整個(gè)數(shù)組或其分段,可調(diào)用該方法。
  • Arrays.deepEquals, Arrays.deepHashCode ——支持嵌套子數(shù)組的 Arrays.equals 或 Arrays.hashCode 版本。
  • Arrays.equals ——如果需要比較兩個(gè)數(shù)組是否相等,可調(diào)用此方法(不可調(diào)用數(shù)組自身的 equals 方法,array.equals 方法未被重寫(xiě),因此只會(huì)比較對(duì)數(shù)組的引用,而非其內(nèi)容。)此方法可以與 Java 5 中的 boxing(裝箱)與 varargs(可變參數(shù))特性并用,以編寫(xiě)類(lèi) equals 方法的簡(jiǎn)單實(shí)現(xiàn)——在比較對(duì)象類(lèi)型之后,將所有類(lèi)字段都傳給 Arrays.equals 即可。
  • Arrays.fill ——將整個(gè)數(shù)組或其分段賦值為給定的值。
  • Arrays.hashCode ——計(jì)算數(shù)組內(nèi)容的 hashcode 值(數(shù)組自身的 hashcode 方法無(wú)法實(shí)現(xiàn)此功能。)此方法可以與 Java 5 中的 boxing(裝箱)與 varargs(可變參數(shù))特性并用,以編寫(xiě)類(lèi) hashcode 方法的簡(jiǎn)單實(shí)現(xiàn)——將所有類(lèi)字段都傳給 Arrays.hashcode 即可。
  • Arrays.sort ——根據(jù)自然排序(natural ordering)規(guī)則,對(duì)整個(gè)數(shù)組或其分段進(jìn)行排序。若要利用已知的 Comparator 對(duì) Object[] 進(jìn)行排序,也有一對(duì) Arrays.sort 方法。
  • Arrays.toString ——打印數(shù)組的具體內(nèi)容。

如果需要將部分?jǐn)?shù)組(或整個(gè)數(shù)組)拷貝到另一個(gè)已有數(shù)組,你需要調(diào)用 System.arraycopy 方法,后者會(huì)將源數(shù)組中指定位置的給定數(shù)量的元素拷貝到目的數(shù)組的指定位置。通常,這是在 Java 中拷貝數(shù)組內(nèi)容的最快方式(不過(guò),在某些情況下,你也可以檢查一下 ByteBuffer 批量拷貝的速度是否更快)。

最后,還有一點(diǎn),任何 Collection(集合) 都可以使用 T[] Collection.toArray( T[] a ) 方法拷貝到數(shù)組中。此方法調(diào)用的常見(jiàn)模式如下:

return coll.toArray( new T[ coll.size() ] );

此方法調(diào)用會(huì)分配足夠大的數(shù)組以存儲(chǔ)整個(gè)集合,因此 toArray 不必要分配很大的數(shù)組用于返回。

單線(xiàn)程集合(Single-threaded collections)

本部分將重點(diǎn)介紹非線(xiàn)程安全(non-thread-safe)集合。這些集合全都存儲(chǔ)于 java.util 包中。其中一些集合類(lèi)型從 Java 1.0 開(kāi)始就有了,現(xiàn)在已經(jīng)不再建議使用(deprecated),但大多數(shù)集合類(lèi)型從 Java 1.4 開(kāi)始啟用。枚舉集合(Enum collections)自 Java 1.5 開(kāi)始出現(xiàn),同時(shí)具備所有集合類(lèi)的泛型支持。PriorityQueue 也是從 Java 1.5 開(kāi)始啟用的。非線(xiàn)程安全集合框架的最新成員是自 Java 1.6 起推出的 ArrayDeque。

Lists(列表)

  • ArrayList ——用處最大的 List 實(shí)現(xiàn)。包含一個(gè)數(shù)組與一個(gè) int 類(lèi)型,后者代表了數(shù)組中首個(gè)未使用元素所在的位置。與其他 List 一樣,ArrayList 可以在需要的時(shí)候進(jìn)行擴(kuò)展。此外,元素讀取時(shí)間固定,在列表尾部更新時(shí)成本很小(復(fù)雜度是固定的),而在頭部更新時(shí)成本很高(復(fù)雜度是線(xiàn)性增長(zhǎng)的),這是因?yàn)? ArrayList 不變量——所有元素在底層數(shù)組中從索引(index)為0處開(kāi)始,這意味著在插入元素時(shí),插入位置右邊的所有元素都要往右移;在移除元素時(shí),移除位置右邊的所有元素都要往左移。由于包含數(shù)組,該集合類(lèi)型易于 CPU 緩存。(不過(guò),也不是特別容易。因?yàn)槠浒?Objects,而后者其實(shí)是指向?qū)嶋H對(duì)象的指針)。
  • LinkedList ——Deque 實(shí)現(xiàn),每個(gè) Node(結(jié)點(diǎn))由一個(gè)值,以及 prev 與 next 指針構(gòu)成。這意味著,元素讀取或更新的復(fù)雜度是線(xiàn)性增長(zhǎng)的(得益于一些優(yōu)化,這些方法遍歷的范圍不會(huì)超過(guò)列表長(zhǎng)度的一半,因此,讀取或更新成本最高的元素位于列表的中間位置)。如果打算編寫(xiě)運(yùn)行更快的 LinkedList 代碼,則需要使用 ListIterators。如果想要編寫(xiě) Queue/Deque 實(shí)現(xiàn)(只需讀取首尾兩個(gè)元素),請(qǐng)轉(zhuǎn)而使用 ArrayDeque。
  • Vector —— ArrayList 先前的版本,包含所有同步方法。請(qǐng)盡量使用 ArrayList。

Queues(隊(duì)列)/deques(雙隊(duì)列)

  • ArrayDeque – Deque implementation based on the array (circular buffer) with head/tail pointers. Unlike LinkedList, this class does not implement List interface, which means that you can not access anything except the first and the last elements. This class is generally preferable to LinkedList for queues/deques due to a limited amount of garbage it generates (old array will be discarded on the extensions).
  • ArrayDeque ——基于數(shù)組(循環(huán)緩沖)的 Deque 實(shí)現(xiàn),帶有頭/尾(head/tail)指針。與 LinkedList 不同,該類(lèi)并不實(shí)現(xiàn) List 接口,這意味著除了首尾元素,無(wú)法讀取其他元素。由于該類(lèi)生成的垃圾較少,在實(shí)現(xiàn)隊(duì)列或雙隊(duì)列時(shí),該類(lèi)比 LinkedList 更加適合(老數(shù)組在擴(kuò)展時(shí)會(huì)被拋棄)。
  • Stack ——后進(jìn)先出(LIFO)隊(duì)列。不要在生產(chǎn)代碼中使用該類(lèi)。可用任意 Deque 實(shí)現(xiàn)替代之(ArrayDeque 優(yōu)先)。
  • PriorityQueue ——基于priority(優(yōu)先級(jí))堆的隊(duì)列。采用自然排序或已知的 Comparator。其主要屬性—— poll/peek/remove/element 方法總是返回隊(duì)列中最小的余留元素。盡管如此,該隊(duì)列實(shí)現(xiàn)了 Iterable,不會(huì)按照排好的次序(或任何特定次序)迭代隊(duì)列。如果只需要隊(duì)列中的最小元素,該隊(duì)列往往比 TreeSet
    之類(lèi)的其他排序集合更可取。

Maps(映射)

  • HashMap ——最常見(jiàn)的一種映射實(shí)現(xiàn),將鍵(key)映射至對(duì)應(yīng)的值(value),僅此而已。如果想要高效率的 hashcode 方法,可以考慮 get/put 方法,它們的復(fù)雜度是固定的。
  • EnumMap ——帶有 enum 鍵的映射。由于已知最大鍵數(shù)量以及內(nèi)置的 enum 至 int 映射,此類(lèi)的運(yùn)行速度往往高于 HashMap。
  • Hashtable —— HashMap 先前的同步化版本,在新產(chǎn)品的代碼中盡量用 HashMap 替代之。
  • IdentityHashMap —— Map 的超特殊版本,違背了 Map 的通用約定:在比較引用時(shí)使用 == 而非調(diào)用 Object.equals 方法。這一屬性使得 IdentityHashMap 在各種圖遍歷算法中大顯神通——你可以在 IdentityHashMap 中輕易地存儲(chǔ)已經(jīng)處理過(guò)的節(jié)點(diǎn),連同一些無(wú)關(guān)數(shù)據(jù)。
  • LinkedHashMap —— HashMap 與 LinkedList 的結(jié)合體,所有元素的插入次序都存儲(chǔ)在 LinkedList 中,也因此,LinkedHashMap 的條目,鍵以及值都以插入次序迭代。就每個(gè)元素的內(nèi)存消耗量而已,這是成本最高的 JDK 集合類(lèi)型。
  • TreeMap ——基于有序?qū)Ш叫?Map 的紅黑樹(shù)。按照自然次序或給定的鍵 Comparator 對(duì)條目進(jìn)行排序。此映射類(lèi)要求 equals 與 Comparable/Comparator.compareTo 的實(shí)現(xiàn)必須一致。此類(lèi)實(shí)現(xiàn)了一個(gè) NavigableMap 接口:它允許獲得少于或多于給定鍵的映射;允許獲得一個(gè) prev/next 條目(基于鍵的排序);允許獲得給定范圍內(nèi)的鍵的映射(這與 SQL
    的 BETWEEN 操作符基本對(duì)應(yīng))以及此方法的許多變體。
  • WeakHashMap ——此映射通常用于數(shù)據(jù)緩存的實(shí)現(xiàn)。它將所有鍵都保存于 WeakReference,這意味著,如果沒(méi)有指向這些鍵對(duì)象的強(qiáng)引用,這些鍵就會(huì)被垃圾回收。另一方面,值卻用強(qiáng)引用保存。因此,你需要確保不存在從值指向鍵的引用,或者將值也保存在弱引用中:m.put(key, new WeakReference(value))。

Sets(集合)

  • HashSet ——基于帶有虛值(每個(gè)值的 Object 均相同) HashMap 的 set 實(shí)現(xiàn)。與 HashMap 的屬性相同。也因?yàn)檫@種實(shí)現(xiàn)方式,此類(lèi)消耗的內(nèi)存比該數(shù)據(jù)類(lèi)型實(shí)際需要的內(nèi)存要多。
  • EnumSet —— enum 值的集合。在 Java 中,每個(gè) enum 都映射至一個(gè) int 類(lèi)型:每個(gè) enum 值映射的 int 都互不相同。這使得 BitSet 之類(lèi)的集合結(jié)構(gòu)成為可能,每個(gè) bit 都映射到一個(gè)不同的 enum 值。此類(lèi)還存在兩種實(shí)現(xiàn)——包含單個(gè) long 類(lèi)型(可存儲(chǔ)64個(gè) enum 值,足夠覆蓋99.9%的用例)的 RegularEnumSet 與包含 long[] 類(lèi)型的 JumboEnumSet。
  • BitSet —— bit 集合。請(qǐng)牢記,可以使用 BitSet 表示整型的稠密集(比如從已知起點(diǎn)開(kāi)始的 id)。此類(lèi)使用 long[] 類(lèi)型存儲(chǔ) bit。
  • LinkedHashSet ——與 HashSet 類(lèi)似,此類(lèi)基于 LinkedHashMap
    類(lèi)實(shí)現(xiàn)。這是以插入次序保存元素的唯一集合類(lèi)。
  • TreeSet ——與 HashSet 類(lèi)似,此類(lèi)基于 TreeMap 實(shí)例。這是標(biāo)準(zhǔn) JDK 的單線(xiàn)程陣營(yíng)中唯一的有序集合。

java.util.Collections

就像針對(duì)數(shù)組的 java.util.Arrays 包一樣,java.util.Collections 包提供了許多處理集合的好方法。

本文將要介紹的第一組方法會(huì)返回集合的各種視圖:

  • Collections.checkedCollection / checkedList / checkedMap / checkedSet / checkedSortedMap / checkedSortedSet —— 會(huì)返回集合的視圖,在運(yùn)行時(shí)檢查所添加元素的類(lèi)型。如果試圖添加類(lèi)型不兼容的元素,會(huì)拋出 ClassCastException 異常。該功能能有效防止運(yùn)行時(shí)造型(runtime casts)。
  • Collections.emptyList / emptyMap / emptySet ——當(dāng)你需要返回不可變的空集合,而又不想分配任何對(duì)象時(shí),此類(lèi)方法便能派上用場(chǎng)。
  • Collections.singleton / singletonList / singletonMap —— 返回帶有單個(gè)條目的不可變 set/list/map。
  • Collections.synchronizedCollection / synchronizedList /
    synchronizedMap / synchronizedSet / synchronizedSortedMap /
    synchronizedSortedSet —— 返回包含所有同步方法的集合視圖(低成本又低效率的多線(xiàn)程方法,仍然不支持put-or-update之類(lèi)的復(fù)合動(dòng)作)。
  • Collections.unmodifiableCollection / unmodifiableList /
    unmodifiableMap / unmodifiableSet / unmodifiableSortedMap /
    unmodifiableSortedSet——返回集合的不可變視圖。當(dāng)需要實(shí)現(xiàn)包含任意集合的不可變對(duì)象時(shí)尤其有用。

本文介紹的第二組方法都因?yàn)橄嗤脑虮慌懦诩现猓?/p>

  • Collections.addAll ——如果要往一個(gè)集合添加一定數(shù)量的元素或一個(gè)數(shù)組的內(nèi)容,調(diào)用此方法。
  • Collections.binarySearch —— 與 Arrays.binarySearch 對(duì)于 arrays(數(shù)組)的作用相同。
  • Collections.disjoint —— 檢查2個(gè)集合之間不存在共同的元素。
  • Collections.fill —— 用給定值替換某個(gè)列表中的所有元素。
  • Collections.frequency —— 給定集合中有多少元素與給定對(duì)象相等。
  • Collections.indexOfSubList / lastIndexOfSubList —— 這些方法與
    String.indexOf(String) / lastIndexOf(String) 相似,它們會(huì)找出給定列表中給定子列表首次或末次出現(xiàn)的情況。
  • Collections.max / min —— 基于自然排序或 Comparator 找出集合中的最大或最小元素。
  • Collections.replaceAll —— 在給定列表中用某個(gè)元素替代另一個(gè)元素。
  • Collections.reverse —— 顛倒給定列表中的元素次序。如果你打算在列表排序之后立即調(diào)用此方法,不如在進(jìn)行元素排序時(shí)使用 Collections.reverseOrder 比較器。
  • Collections.rotate —— 根據(jù)給定距離旋轉(zhuǎn)列表中的元素。
  • Collections.shuffle ——打亂列表的排序。注意,你可以為此方法提供自己的隨機(jī)生成器,可以是 java.util.Random,java.util.ThreadLocalRandom 或 java.security.SecureRandom。
  • Collections.sort —— 根據(jù)自然排序或給定的 Comparator 對(duì)列表進(jìn)行排序。
  • Collections.swap —— 根據(jù)給定的位置交換列表中的2個(gè)元素(許多開(kāi)發(fā)者都親自編寫(xiě)此方法)。

并發(fā)集合

本部分將介紹 java.util.concurrent 包中提供的線(xiàn)程安全(thread-safe)集合類(lèi)型。這些集合的主要特性在于能確保其方法的原子執(zhí)行(atomic execution)。不過(guò),不要忘記,涉及多個(gè)方法調(diào)用的 “add-or-update” 或 “check-then-update” 等復(fù)合動(dòng)作(compound actions)仍然應(yīng)該同步。因?yàn)椋趶?fù)合動(dòng)作第一步中查詢(xún)到的信息在執(zhí)行第二個(gè)步驟之前可能已經(jīng)失效。

大多數(shù)并發(fā)集合類(lèi)型從 Java 1.5 開(kāi)始引入。ConcurrentSkipListMap / ConcurrentSkipListSet 以及 LinkedBlockingDeque 是在 Java 1.6 開(kāi)始啟用的。在 Java 1.7 中的最近更新為 ConcurrentLinkedDeque 與 LinkedTransferQueue 的加入。

Lists(列表)

  • CopyOnWriteArrayList ——列表實(shí)現(xiàn),針對(duì)每次更新都創(chuàng)建一個(gè)底層數(shù)組的新拷貝。這一操作的成本很高,因此,當(dāng)遍歷的次數(shù)遠(yuǎn)大于更新時(shí)使用此類(lèi)比較合適。此集合類(lèi)型的常見(jiàn)用例為 listeners/observers 集合。

Queues(隊(duì)列)/deques(雙隊(duì)列)

  • ArrayBlockingQueue —— 包含一個(gè)數(shù)組類(lèi)的有界阻塞隊(duì)列。無(wú)法調(diào)整大小,因此,當(dāng)向滿(mǎn)的隊(duì)列添加一個(gè)元素時(shí),該方法調(diào)用會(huì)遭到阻塞,直到另一個(gè)線(xiàn)程從該隊(duì)列中提取出了一個(gè)元素。
  • ConcurrentLinkedDeque / ConcurrentLinkedQueue ——基于鏈表(linked
    list)的無(wú)界隊(duì)列/雙隊(duì)列。往該隊(duì)列中添加元素不會(huì)遭到阻塞,但是要求此類(lèi)集合的使用者(consumer)必須與其產(chǎn)出者(producer)保持至少相同的工作效率,否則就會(huì)出現(xiàn)內(nèi)存耗盡的情況。此類(lèi)還相當(dāng)依賴(lài) CAS (compare-and-set) 操作。
  • DelayQueue ——由 Delayed(延遲) 元素組成的無(wú)界阻塞隊(duì)列。其元素只有在延遲過(guò)期之后才能從隊(duì)列中剔除。隊(duì)首是剩余延遲值最小(包括負(fù)值,代表延遲已經(jīng)過(guò)期)的元素。當(dāng)想要實(shí)現(xiàn)一個(gè)由延遲任務(wù)組成的隊(duì)列時(shí)(無(wú)需手動(dòng)實(shí)現(xiàn),使用 ScheduledThreadPoolExecutor 即可),此隊(duì)列便能派上用場(chǎng)。
  • LinkedBlockingDeque / LinkedBlockingQueue ——基于鏈表(linked list)的可選有界(可以在創(chuàng)建時(shí)指定最大容量,也可以不指定)隊(duì)列/雙隊(duì)列。以 ReentrantLock-s 為空/滿(mǎn)條件。
  • LinkedTransferQueue ——基于鏈表(linked list)的無(wú)界隊(duì)列。除了普通的隊(duì)列操作,此類(lèi)還擁有一組傳遞方法(transfer methods),允許產(chǎn)出者直接向等待中的使用者發(fā)送消息,從而解決了在隊(duì)列中存儲(chǔ)元素的需求。這是一個(gè)基于 CAS 操作的無(wú)鎖(lock-free)集合類(lèi)型。
  • PriorityBlockingQueue —— PriorityQueue 的無(wú)界阻塞隊(duì)列版。
  • SynchronousQueue——不帶任何內(nèi)部容量的阻塞隊(duì)列。因此,任何插入請(qǐng)求必須等待對(duì)應(yīng)的刪除請(qǐng)求,反之亦然。如果你不需要 Queue 接口,同樣的功能可以通過(guò) Exchanger 實(shí)現(xiàn)。

Maps(映射)

  • ConcurrentHashMap ——對(duì) get 操作全并發(fā)、對(duì) put 操作可配置并發(fā)的散列表(hash table)。該并發(fā)等級(jí)可通過(guò)構(gòu)造函數(shù)參數(shù)(默認(rèn)為16) concurrencyLevel 進(jìn)行調(diào)整,該參數(shù)定義了映射內(nèi)的劃分情況。在 put 操作中只有更新后的劃分會(huì)被鎖定。請(qǐng)牢記,此映射類(lèi)型并不是 HashMap 算法的線(xiàn)程安全替代品 ——任何對(duì)此映射(或其他并發(fā)集合類(lèi))的 “get-then-put” 序列方法調(diào)用都必須是外部同步的。
  • ConcurrentSkipListMap ——基于跳躍表(skip list)的 ConcurrentNavigableMap 實(shí)現(xiàn)。本質(zhì)上,此集合類(lèi)可以作為 TreeMap 的線(xiàn)程安全替代物使用。

Sets(集合)

  • ConcurrentSkipListSet ——采用 ConcurrentSkipListMap 類(lèi)進(jìn)行存儲(chǔ)的并發(fā)集合。
  • CopyOnWriteArraySet ——采用 CopyOnWriteArrayList 類(lèi)進(jìn)行存儲(chǔ)的并發(fā)集合。

另請(qǐng)參閱

推薦閱讀

如果你想對(duì) Java 集合類(lèi)有更深入的了解,筆者建議你從下面的書(shū)中找一本閱讀。

總結(jié)

以下是所有 JDK 集合類(lèi)的簡(jiǎn)單總結(jié):

這里寫(xiě)圖片描述

這里寫(xiě)圖片描述

這里寫(xiě)圖片描述

這里寫(xiě)圖片描述

OneAPM 能為您提供端到端的 Java 應(yīng)用性能解決方案,我們支持所有常見(jiàn)的 Java 框架及應(yīng)用服務(wù)器,助您快速發(fā)現(xiàn)系統(tǒng)瓶頸,定位異常根本原因。分鐘級(jí)部署,即刻體驗(yàn),Java 監(jiān)控從來(lái)沒(méi)有如此簡(jiǎn)單。想閱讀更多技術(shù)文章,請(qǐng)?jiān)L問(wèn) OneAPM 官方技術(shù)博客

本文轉(zhuǎn)自 OneAPM 官方博客

原文地址:http://java-performance.info/java-collections-overview/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,991評(píng)論 19 139
  • 集合框架體系概述 為什么出現(xiàn)集合類(lèi)?方便多個(gè)對(duì)象的操作,就對(duì)對(duì)象進(jìn)行存儲(chǔ),集合就是存儲(chǔ)對(duì)象最常用的一種方法. 數(shù)組...
    acc8226閱讀 792評(píng)論 0 1
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,767評(píng)論 18 399
  • 概述 Java集合框架由Java類(lèi)庫(kù)的一系列接口、抽象類(lèi)以及具體實(shí)現(xiàn)類(lèi)組成。我們這里所說(shuō)的集合就是把一組對(duì)象組織到...
    absfree閱讀 1,285評(píng)論 0 10
  • 一、業(yè)務(wù)場(chǎng)景 在廣告追蹤系統(tǒng)中,我們通過(guò)提供SDK給用戶(hù),把各種各樣的用戶(hù)數(shù)據(jù)采集到我們的服務(wù)器中,然后通過(guò)MR計(jì)...
    yannhuang閱讀 1,749評(píng)論 0 10