collections.compare(() -> { jdk; apache; eclipse; guava});...• apache commons collection –...
TRANSCRIPT
Collections.compare(() -> { JDK; Apache; Eclipse; Guava...}); Nikhil J. Nanivadekar
#CollectionsCompare #GIDS17 @NikhilNanivade
Agenda
1. Introduction 2. History of Java util collections framework 3. Gaps in use cases from the timeline 4. Timeline with other collection frameworks 5. Memory characteristics 6. Use case, domain diagrams 7. Deep dive in use case
#CollectionsCompare #GIDS17 @NikhilNanivade
Authors
• Donald Raab (@TheDonRaab) • Leonardo Lima (@leomrlima) • Nikhil J. Nanivadekar (@NikhilNanivade)
#CollectionsCompare #GIDS17 @NikhilNanivade
Speaker
Nikhil J. Nanivadekar – Mechanical Engineer – Software developer – Vice President, Technology at Goldman Sachs – From Pune, Maharashtra currently in Salt Lake City,
Utah
java.util Collections
#CollectionsCompare #GIDS17 @NikhilNanivade
java.util Collections
• Java Collection Framework has been around since 1998/JDK 1.2. Very basic but critical collection support for Java.
• Interfaces: Maps and Collections (List, Set, Queue, Deque)
• Implementations: Basic and Concurrent versions of the interfaces, sorted and concurrent as well
• Algorithms: Sorting, Shuffling, Routine Data Manipulation, Searching, Composition
• Best way to get started is using the simple and concurrent tutorials
#CollectionsCompare #GIDS17 @NikhilNanivade
Java Collections Frameworks Java 2 1998
• Interfaces • Collection • List • Set • Map • SortedSet • SortedMap
Java 5 2005
• Generics • For-each loop • Interfaces
• Iterable • Queue • ConcurrentMap • BlockingQueue
Java 6 2006
•Interfaces •NavigableSet •NavigableMap •Deque •BlockingDeque •ConcurrentNavigableMap
Java 7 2011
• Interfaces • TransferQueue
Java 8 2014
• Lambdas • Method Refs • Default Methods • Interfaces
• BaseStream • Stream • IntStream • LongStream • DoubleStream • Collector • Spliterator • PrimitiveIterator
!java.util Collections?
#CollectionsCompare #GIDS17 @NikhilNanivade
!java.util Collections
• We’re considering 4 collection frameworks, in alphabetical order:
• Apache Commons Collection – version 4.1
• Eclipse Collections (Formerly GS Collections) – version 8.1.0
• Google Guava – version 21.0
• Javaslang (now called Vavr) – version 2.1.0-alpha
#CollectionsCompare #GIDS17 @NikhilNanivade
Collection Framework Timelines
Java 2 1998
•Jakarta Collections 1.0 •2001
•Apache Collections 3.0 •2004
Java 6 2006
•Google Collections 1.0 •Dec. 2009
Java 7 2011
•Google Guava 10.0 •Sept. 2011
•GS Collections 1.0 •Jan. 2012
•Apache Collections 4.0 •Nov. 2013
Java 8 2014
•Javaslang 1.0 •Mar. 2014
•Apache Collections 4.1 •Nov. 2015
•Eclipse Collections 7.0 •Jan. 2016
•Eclipse Collections 8.0 (Java 8) •Sept. 2016
•Google Guava 20.0 •Oct. 2016
•Javaslang 2.1a •Nov. 2016
March 2017
•Google Guava 21.0 (Java 8) •Jan. 2017
•Eclipse Collections 8.1 •Mar. 2017
Collections.compare();
#CollectionsCompare #GIDS17 @NikhilNanivade
Use Case – Deck of Cards
The Collections Compare Project: https://github.com/nikhilnanivadekar/CollectionsCompare
#CollectionsCompare #GIDS17 @NikhilNanivade
Problem Statement – Deck of Cards
1. Create Deck of Cards – Store Cards in an “Immutable” SortedSet
(Cartesian product of Suit x Rank) – Group the cards by Suit in an “Immutable” SortedSet
“Multimap” (Group By)
2. Get the number of cards – Count By Suit returning “Multiset” or “Bag” – Count By Rank returning “Multiset” or “Bag”
3. Deal five hands of five cards each – Return the cards as an “Immutable” List of five Sets of five
cards
#CollectionsCompare #GIDS17 @NikhilNanivade
Performance Benchmarks
• JMH – Java Microbenchmark Harness • http://openjdk.java.net/projects/code-tools/jmh/ • Measure Reported – Operations per second • Bigger numbers are better • 4 Core Intel I7, 50 Warm-up iterations, 30
measurement iterations, two forks
#CollectionsCompare #GIDS17 @NikhilNanivade
Problem Statement – Deck of Cards
1. Create Deck of Cards – Store Cards in an “Immutable” SortedSet
(Cartesian product of Suit x Rank) – Group the cards by Suit in an “Immutable” SortedSet
“Multimap” (Group By)
2. Get the number of cards – Count By Suit returning “Multiset” or “Bag” – Count By Rank returning “Multiset” or “Bag”
3. Deal five hands of five cards each – Return the cards as an “Immutable” List of five Sets of five
cards
#CollectionsCompare #GIDS17 @NikhilNanivade
Performance Test – Deck of Cards
102,037
79,343 76,982
56,224
91,017
0
20,000
40,000
60,000
80,000
100,000
120,000
Scor
e op
s/s
Framework
Deck of Cards
Apache EC Guava Javaslang JDK
#CollectionsCompare #GIDS17 @NikhilNanivade
A Deck of Cards – Only the Types public class JDK8DeckOfCards { private SortedSet<Card> cards; private Map<Suit, SortedSet<Card>> cardsBySuit;
public class ApacheCommonsDeckOfCards { private SortedSet<Card> cards; private MultiValuedMap<Suit, Card> cardsBySuit;
public class EclipseCollectionsDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSortedSetMultimap<Suit, Card> cardsBySuit;
public class GoogleGuavaDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSetMultimap<Suit, Card> cardsBySuit;
public class JavaSlangDeckOfCards { private SortedSet<Card> cards; private Map<Suit, ? extends SortedSet<Card>> cardsBySuit;
#CollectionsCompare #GIDS17 @NikhilNanivade
A Deck of Cards – Only the Types public class JDK8DeckOfCards { private SortedSet<Card> cards; private Map<Suit, SortedSet<Card>> cardsBySuit;
public class ApacheCommonsDeckOfCards { private SortedSet<Card> cards; private MultiValuedMap<Suit, Card> cardsBySuit;
public class EclipseCollectionsDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSortedSetMultimap<Suit, Card> cardsBySuit;
public class GoogleGuavaDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSetMultimap<Suit, Card> cardsBySuit;
public class JavaSlangDeckOfCards { private SortedSet<Card> cards; private Map<Suit, ? extends SortedSet<Card>> cardsBySuit;
#CollectionsCompare #GIDS17 @NikhilNanivade
A Deck of Cards – Only the Types public class JDK8DeckOfCards { private SortedSet<Card> cards; private Map<Suit, SortedSet<Card>> cardsBySuit;
public class ApacheCommonsDeckOfCards { private SortedSet<Card> cards; private MultiValuedMap<Suit, Card> cardsBySuit;
public class EclipseCollectionsDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSortedSetMultimap<Suit, Card> cardsBySuit;
public class GoogleGuavaDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSetMultimap<Suit, Card> cardsBySuit;
public class JavaSlangDeckOfCards { private SortedSet<Card> cards; private Map<Suit, ? extends SortedSet<Card>> cardsBySuit;
#CollectionsCompare #GIDS17 @NikhilNanivade
A Deck of Cards – Only the Types public class JDK8DeckOfCards { private SortedSet<Card> cards; private Map<Suit, SortedSet<Card>> cardsBySuit;
public class ApacheCommonsDeckOfCards { private SortedSet<Card> cards; private MultiValuedMap<Suit, Card> cardsBySuit;
public class EclipseCollectionsDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSortedSetMultimap<Suit, Card> cardsBySuit;
public class GoogleGuavaDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSetMultimap<Suit, Card> cardsBySuit;
public class JavaSlangDeckOfCards { private SortedSet<Card> cards; private Map<Suit, ? extends SortedSet<Card>> cardsBySuit;
#CollectionsCompare #GIDS17 @NikhilNanivade
A Deck of Cards – Only the Types public class JDK8DeckOfCards { private SortedSet<Card> cards; private Map<Suit, SortedSet<Card>> cardsBySuit;
public class ApacheCommonsDeckOfCards { private SortedSet<Card> cards; private MultiValuedMap<Suit, Card> cardsBySuit;
public class EclipseCollectionsDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSortedSetMultimap<Suit, Card> cardsBySuit;
public class GoogleGuavaDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSetMultimap<Suit, Card> cardsBySuit;
public class JavaSlangDeckOfCards { private SortedSet<Card> cards; private Map<Suit, ? extends SortedSet<Card>> cardsBySuit;
#CollectionsCompare #GIDS17 @NikhilNanivade
A Deck of Cards – Only the Types public class JDK8DeckOfCards { private SortedSet<Card> cards; private Map<Suit, SortedSet<Card>> cardsBySuit;
public class ApacheCommonsDeckOfCards { private SortedSet<Card> cards; private MultiValuedMap<Suit, Card> cardsBySuit;
public class EclipseCollectionsDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSortedSetMultimap<Suit, Card> cardsBySuit;
public class GoogleGuavaDeckOfCards { private ImmutableSortedSet<Card> cards; private ImmutableSetMultimap<Suit, Card> cardsBySuit;
public class JavaSlangDeckOfCards { private SortedSet<Card> cards; private Map<Suit, ? extends SortedSet<Card>> cardsBySuit;
#CollectionsCompare #GIDS17 @NikhilNanivade
Problem Statement – Deck of Cards
1. Create Deck of Cards – Store Cards in an “Immutable” SortedSet
(Cartesian product of Suit x Rank) – Group the cards by Suit in an “Immutable” SortedSet
“Multimap” (Group By)
2. Get the number of cards – Count By Suit returning “Multiset” or “Bag” – Count By Rank returning “Multiset” or “Bag”
3. Deal five hands of five cards each – Return the cards as an “Immutable” List of five Sets of five
cards
#CollectionsCompare #GIDS17 @NikhilNanivade
Shared Code – Cartesian Product public static Stream<Card> streamCards() { return Card.cartesianProduct( EnumSet.allOf(Rank.class), EnumSet.allOf(Suit.class), Card::new); } private static <A, B, C> Stream<C> cartesianProduct( Set<A> set1, Set<B> set2, Function2<A, B, C> function) { return set1.stream().flatMap(first -> set2.stream().map(second -> function.apply(first, second))); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Performance Test – Cartesian Product
185,087 203,660
465,999
127,439 114,634
0
50,000
100,000
150,000
200,000
250,000
300,000
350,000
400,000
450,000
500,000
Scor
e op
s/s
Framework
Cartesian Product
Apache EC Guava Javaslang JDK
#CollectionsCompare #GIDS17 @NikhilNanivade
JDK Collections – Cartesian Product public class JDK8DeckOfCards { private SortedSet<Card> cards; public JDK8DeckOfCards() { this.cards = Card.streamCards() .collect(Collectors.collectingAndThen( Collectors.toCollection(TreeSet::new), Collections::unmodifiableSortedSet)); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Apache Collections – Cartesian Product public class ApacheCommonsDeckOfCards { private SortedSet<Card> cards; public ApacheCommonsDeckOfCards() { this.cards = Card.streamCards() .collect(Collectors.collectingAndThen( Collectors.toCollection(TreeSet::new), Collections::unmodifiableSortedSet)); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Eclipse Collections – Cartesian Product public class EclipseCollectionsDeckOfCards { private ImmutableSortedSet<Card> cards; public EclipseCollectionsDeckOfCards() { this.cards = SortedSets.immutable.with( Card.streamCards() .toArray(Card[]::new)); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Google Guava – Cartesian Product public class GoogleGuavaDeckOfCards { private ImmutableSortedSet<Card> cards; public GoogleGuavaDeckOfCards() { this.cards = Card.streamCards() .collect(ImmutableSortedSet .toImmutableSortedSet( Comparator.naturalOrder())); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Javaslang – Cartesian Product public class JavaSlangDeckOfCards { private SortedSet<Card> cards; public JavaSlangDeckOfCards() { this.cards = Card.streamCards() .collect(TreeSet.collector()); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Problem Statement – Deck of Cards
1. Create Deck of Cards – Store Cards in an “Immutable” SortedSet
(Cartesian product of Suit x Rank) – Group the cards by Suit in an “Immutable” SortedSet
“Multimap” (Group By)
2. Get the number of cards – Count By Suit returning “Multiset” or “Bag” – Count By Rank returning “Multiset” or “Bag”
3. Deal five hands of five cards each – Return the cards as an “Immutable” List of five Sets of five
cards
#CollectionsCompare #GIDS17 @NikhilNanivade
Performance Test - groupBy
540,396
183,848 231,321
176,412
353,651
-
100,000
200,000
300,000
400,000
500,000
600,000
Scor
e op
s/s
Framework
groupBy
Apache EC Guava Javaslang JDK
#CollectionsCompare #GIDS17 @NikhilNanivade
JDK Collections – Group By public class JDK8DeckOfCards { private Map<Suit, SortedSet<Card>> cardsBySuit; public JDK8DeckOfCards() { this.cardsBySuit = Collections.unmodifiableMap( this.cards.stream() .collect(Collectors.groupingBy( Card::getSuit, Collectors.mapping( Function.identity(), Collectors.collectingAndThen( Collectors.toCollection(TreeSet::new), Collections::unmodifiableSortedSet))))); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Apache Collections – Group By public class ApacheCommonsDeckOfCards { private MultiValuedMap<Suit, Card> cardsBySuit; public ApacheCommonsDeckOfCards() { SetValuedMap<Suit, Card> cbs = MultiMapUtils.newSetValuedHashMap(); this.cards.forEach(card -> cbs.put(card.getSuit(), card)); this.cardsBySuit = MultiMapUtils.unmodifiableMultiValuedMap(cbs); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Eclipse Collections – Group By public class EclipseCollectionsDeckOfCards { private ImmutableSortedSetMultimap<Suit, Card> cardsBySuit; public EclipseCollectionsDeckOfCards() { this.cardsBySuit = this.cards.groupBy(Card::getSuit); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Google Guava – Group By public class GoogleGuavaDeckOfCards { private ImmutableSetMultimap<Suit, Card> cardsBySuit; public GoogleGuavaDeckOfCards() { ImmutableSetMultimap.Builder<Suit, Card> builder = new ImmutableSetMultimap.Builder<Suit, Card>() .orderValuesBy(Comparator.naturalOrder()); this.cards.forEach(card -> builder.put(card.getSuit(), card)); this.cardsBySuit = builder.build(); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Javaslang – Group By public class JavaSlangDeckOfCards { private Map<Suit, ? extends SortedSet<Card>> cardsBySuit; public JavaSlangDeckOfCards() { this.cardsBySuit = this.cards.groupBy(Card::getSuit); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Performance Test – Deck of Cards
102,037
79,343 76,982
56,224
91,017
0
20,000
40,000
60,000
80,000
100,000
120,000
Scor
e op
s/s
Framework
Deck of Cards
Apache EC Guava Javaslang JDK
540,396
183,848 231,321 176,412 353,651
-
500,000
1,000,000
Scor
e op
s/s
Framework
groupBy
Apache EC Guava Javaslang JDK
185,087 203,660
465,999
127,439 114,634
0
200,000
400,000
600,000
Scor
e op
s/s
Framework
Cartesian Product
Apache EC Guava Javaslang JDK
#CollectionsCompare #GIDS17 @NikhilNanivade
Problem Statement – Deck of Cards
1. Create Deck of Cards – Store Cards in an “Immutable” SortedSet
(Cartesian product of Suit x Rank) – Group the cards by Suit in an “Immutable” SortedSet
“Multimap” (Group By)
2. Get the number of cards – Count By Suit returning “Multiset” or “Bag” – Count By Rank returning “Multiset” or “Bag”
3. Deal five hands of five cards each – Return the cards as an “Immutable” List of five Sets of five
cards
#CollectionsCompare #GIDS17 @NikhilNanivade
Performance Test - countsBySuit
706,272
1,096,527
533,728 440,786
724,526
0
200,000
400,000
600,000
800,000
1,000,000
1,200,000
Scor
e op
s/s
Framework
Apache EC Guava Javaslang JDK
#CollectionsCompare #GIDS17 @NikhilNanivade
Performance Test - countsByRank
539,252
827,986
444,832 390,134
591,869
0
100,000
200,000
300,000
400,000
500,000
600,000
700,000
800,000
900,000
Scor
e op
s/s
Framework
Apache EC Guava Javaslang JDK
#CollectionsCompare #GIDS17 @NikhilNanivade
JDK Collections – Count By
public Map<Suit, Long> countsBySuit() { return this.cards.stream() .collect(Collectors.groupingBy( Card::getSuit, Collectors.counting())); } public Map<Rank, Long> countsByRank() { return this.cards.stream() .collect(Collectors.groupingBy( Card::getRank, Collectors.counting())); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Apache Collections – Count By
public Bag<Suit> countsBySuit() { return this.cards.stream() .map(Card::getSuit) .collect(Collectors.toCollection(HashBag::new)); } public MultiSet<Rank> countsByRank() { return this.cards.stream() .map(Card::getRank) .collect(Collectors.toCollection( HashMultiSet::new)); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Eclipse Collections – Count By
public Bag<Suit> countsBySuit() { return this.cards.asLazy() .collect(Card::getSuit) .toBag(); } public Bag<Rank> countsByRank() { return this.cards.asLazy() .collect(Card::getRank) .toBag(); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Google Guava – Count By public Multiset<Suit> countsBySuit() { return this.cards.stream() .map(Card::getSuit) .collect(Collectors.toCollection( HashMultiset::create)); } public Multiset<Rank> countsByRank() { return this.cards.stream() .map(Card::getRank) .collect(Collectors.toCollection( HashMultiset::create)); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Javaslang – Count By public java.util.Map<Suit, Long> countsBySuit() { return this.cards.collect( Collectors.groupingBy( Card::getSuit, Collectors.counting())); } public java.util.Map<Rank, Long> countsByRank() { return this.cards.collect( Collectors.groupingBy( Card::getRank, Collectors.counting())); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Problem Statement – Deck of Cards
1. Create Deck of Cards – Store Cards in an “Immutable” SortedSet
(Cartesian product of Suit x Rank) – Group the cards by Suit in an “Immutable” SortedSet
“Multimap” (Group By)
2. Get the number of cards – Count By Suit returning “Multiset” or “Bag” – Count By Rank returning “Multiset” or “Bag”
3. Deal five hands of five cards each – Return the cards as an “Immutable” List of five Sets of
five cards
#CollectionsCompare #GIDS17 @NikhilNanivade
Performance Test – Deal Hands
291,488
502,448
305,673
372,466
300,975
0
100,000
200,000
300,000
400,000
500,000
600,000
Scor
e op
s/s
Framework
Apache EC Guava Javaslang JDK
#CollectionsCompare #GIDS17 @NikhilNanivade
JDK Collections – Deal Hands public List<Set<Card>> dealHands( Deque<Card> shuffled, int hands, int cardsPerHand) { return IntStream.range(0, hands) .mapToObj(i -> this.deal(shuffled, cardsPerHand)) .collect( Collectors.collectingAndThen( Collectors.toList(), Collections::unmodifiableList)); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Apache Collections – Deal Hands public List<Set<Card>> dealHands( Deque<Card> shuffled, int hands, int cardsPerHand) { return IntStream.range(0, hands) .mapToObj(i -> this.deal(shuffled, cardsPerHand)) .collect( Collectors.collectingAndThen( Collectors.toList(), Collections::unmodifiableList)); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Eclipse Collections – Deal Hands
public ImmutableList<Set<Card>> dealHands( MutableStack<Card> shuffled, int hands, int cardsPerHand) { return IntInterval.oneTo(hands) .collect(i -> this.deal(shuffled, cardsPerHand)); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Google Guava – Deal Hands
public ImmutableList<Set<Card>> dealHands( Deque<Card> shuffled, int hands, int cardsPerHand) { return IntStream.range(0, hands) .mapToObj(i -> this.deal(shuffled, cardsPerHand)) .collect(ImmutableList.toImmutableList()); }
#CollectionsCompare #GIDS17 @NikhilNanivade
Javaslang – Deal Hands public List<Set<Card>> dealHands( Stack<Card> shuffled, int hands, int cardsPerHand) { List<Set<Card>> list = List.empty(); for (int i = 0; i < hands; i++) { Tuple2<Set<Card>, ? extends Stack<Card>> tuple2 = this.deal(shuffled, cardsPerHand); shuffled = tuple2._2(); list = list.append(tuple2._1()); } return list; }
Memory Benchmarks
#CollectionsCompare #GIDS17 @NikhilNanivade
Memory Benchmarks
• ObjectExplorer, by Dimitris Andrew • Open Source under Apache License 2.0 • Measure Reported –
– Memory (Kb) vs Size – Memory (Kb) vs List, Set, Map with 1,000,000 elements
• Smaller the better
Sources – GitHub:
https://github.com/DimitrisAndreou/memory-measurer – Found from StackOverflow:
http://stackoverflow.com/a/9368930/5182052
#CollectionsCompare #GIDS17 @NikhilNanivade
List<Integer>
#CollectionsCompare #GIDS17 @NikhilNanivade
List<Integer>
#CollectionsCompare #GIDS17 @NikhilNanivade
List<String>
#CollectionsCompare #GIDS17 @NikhilNanivade
List<String>
#CollectionsCompare #GIDS17 @NikhilNanivade
Set<Integer>
#CollectionsCompare #GIDS17 @NikhilNanivade
Set<Integer>
#CollectionsCompare #GIDS17 @NikhilNanivade
Set<String>
#CollectionsCompare #GIDS17 @NikhilNanivade
Set<String>
#CollectionsCompare #GIDS17 @NikhilNanivade
Map<Integer, Integer>
#CollectionsCompare #GIDS17 @NikhilNanivade
Map<Integer, Integer>
#CollectionsCompare #GIDS17 @NikhilNanivade
Map<String, String>
#CollectionsCompare #GIDS17 @NikhilNanivade
Map<String, String>
Summary
#CollectionsCompare #GIDS17 @NikhilNanivade
Link
• The Collections Compare Project https://github.com/nikhilnanivadekar/CollectionsCompare
#CollectionsCompare #GIDS17 @NikhilNanivade
Collection Framework Comparison Feature JDK Apache Guava Eclipse Javaslang 1st, 2nd, 3rd
List, Set, Map ✔ ✖ ✔ JDK, EC, JS
Multiset / Bag ✖ ✔ ✔ ✔ ✖ GG, EC, AC
Multimap ✖ ✔ ✔ ✔ ✔ GG, EC, AC
BiMap ✖ ✔ ✔ ✔ ✖ GG, EC, AC
Stack ✔ ✖ ✔ ✔ EC, JDK, JS
Tree / Trie ✖ ✔ ✖ ✖ ✔ JS, AC
Table ✖ ✖ ✔ ✖ ✖ GG
Additional Types ✔ ✔ ✔ AC, JDK, GG
Immutable? ✖ ✖ ✔ ✔ ✔ JS, EC, GG
Primitives? ✖ ✔ ✖ EC, JDK, GG
Fluent API ✔ ✔ EC, JS, JDK
(E), (L), (S), (P)* , ✔, ✔, ✔
, , ✔, ✖
✖, , ✔, ✖
✔, ✔, ✔, ✔
✔, ✔, ✔, ✖ EC, JDK, JS
Thanks! The Collections Compare Project
https://github.com/nikhilnanivadekar/CollectionsCompare