SlideShare a Scribd company logo
#Devoxx
LinkedList to ArrayList
The Full Story!
José Paumard
#Devoxx #ListJ9 @JosePaumard
It all begin…
• November 22nd 2015 by a tweet
#Devoxx #ListJ9 @JosePaumard
It all begin…
• Then the discussion started
#Devoxx #ListJ9 @JosePaumard
It all begin…
• And about 30 tweets later:
#Devoxx #ListJ9 @JosePaumard
And did not ended there!
• And around midnight, 7th nov. 2016:
• Since this is the subject of this Uni, we will take more
time…
Linked to ArrayList: the full story
#Devoxx #ListJ9 @JosePaumard
Questions ?
#ListJ9
Questions?
#ListJ9
#Devoxx #ListJ9 @JosePaumard
• This discussion ArrayList vs LinkedList is no troll…
 Even if it looks like one!
• The question is :
Is one of these implementations better than the other?
• And there is an answer to this question!
And the conclusion is…
#Devoxx #ListJ9 @JosePaumard
And the conclusion is…
• To fully understand this answer, we need to
understand many other things
#Devoxx #ListJ9 @JosePaumard
And the conclusion is…
• To fully understand this answer, we need to
understand many other things
• And once we have answered it (almost) fully , many
other questions will arise!
#Devoxx #ListJ9 @JosePaumard
1st part
• Algorithms
• Complexity
• Implementation
• CPU architecture
• « cache friendly »
• Slides, bullet points…
#Devoxx #ListJ9 @JosePaumard
2nd part
• Implementation of Set, List et Map (with a surprise!)
• Live coding!
• Some more slides but not that many
 But don’t worry, still bullet points
#Devoxx #ListJ9 @JosePaumard
Where to begin?
• In fact there are several ways to begin…
#Devoxx #ListJ9 @JosePaumard
Where to begin?
• In fact there are several ways to begin…
• Algorithms!
#Devoxx #ListJ9 @JosePaumard
Where to begin?
• In fact there are several ways to begin…
• Algorithms!
• Implementation vs CPU architecture
#Devoxx #ListJ9 @JosePaumard
Where to begin?
• In fact there are several ways to begin…
• Algorithms!
• Implementation vs CPU architecture
• Use cases
#Devoxx #ListJ9 @JosePaumard
What do we know?
1) ArrayList is built on an array
2) LinkedList is built on a linked list
And we have results on this
#Devoxx #ListJ9 @JosePaumard
Approach
• Take a close look at the basic operations on lists
• Create / modify:
 Add an element at the end of at the beginning of a list
 Removing an element by its index
 Removing an element
 The contains() method
 The removeIf() and sort() methods
#Devoxx #ListJ9 @JosePaumard
Approach
• Take a close look at the basic operations on lists
• Add:
List<String> list = ...
list.add("one"); // add
list.add(12, "one"); // insert
#Devoxx #ListJ9 @JosePaumard
Approach
• Take a close look at the basic operations on lists
• Remove:
List<String> list = ...
list.remove("one"); // remove
list.remove(12); // remove by index
#Devoxx #ListJ9 @JosePaumard
Approach
• Take a close look at the basic operations on lists
• Sort / removeIf:
List<String> list = ...
list.sort(comparingBy(String::length)); // sort
list.removeIf(s -> s.length() > 10); // remove if
#Devoxx #ListJ9 @JosePaumard
Approach
• Take a close look at the basic operations on lists
• Read operations:
 Iterate
 Read an element with its index
 Building a Stream
#Devoxx #ListJ9 @JosePaumard
Approach
• Take a close look at the basis operations on lists
• Read operations:
List<String> list = ...
list.forEach(System.out::println); // list traversal
list.get(12); // access by index
list.stream(); // stream creation
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Access to the nth element: almost free
• Adding an element: almost free, but…
• Insertion: shift the elements to the right
• Deletion: shift the elements to the left
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Access to the nth element: almost free
n
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Adding an element: almost free, but…
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
elementData = Arrays.copyOf(elementData, newCapacity);
}
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Adding an element: almost free, but…
• Sometimes the array has to be enlarge
• But we can fix the size of the array when we build it
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Adding an element: almost free, but…
• Sometimes the array has to be enlarge
• Bytheway growing a HashSet is much more
expensive…
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Insertion
n, one
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Insertion
public void add(int index, E element) {
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Insertion
one
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Suppression
n
X
#Devoxx #ListJ9 @JosePaumard
ArrayList
• Built on an array
• Suppression
public E remove(int index) {
E oldValue = elementData(index);
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
return oldValue;
}
#Devoxx #ListJ9 @JosePaumard
ArrayList
• (Very) Early conclusion
• Accessing an element is fast!
• Adding is fast, if there is no overflow
• Random insert / delete: overhead to handle the
« holes »
#Devoxx #ListJ9 @JosePaumard
LinkedList
• Built on a double linked list
• Access to the nth element
• Adding an element at the end of the list
• Insertion
• Deletion
#Devoxx #ListJ9 @JosePaumard
LinkedList
• Base structure
next prev
item
Node
next prev
item
Node
next prev
item
Node
first last
#Devoxx #ListJ9 @JosePaumard
LinkedList
• Built on a double linked list
• Access to the nth element: run through all the elements
• Adding: free, just a modification of pointers
• Insertion: free, just a modification of pointers
• Suppression: free, just a modification of pointers
#Devoxx #ListJ9 @JosePaumard
LinkedList
• Access to the nth element
Node<E> node(int index) {
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
}
// same for last
}
#Devoxx #ListJ9 @JosePaumard
LinkedList
• Access to the nth element: one has to visit all the
elements and count them, until the nth is found
• We say that the complexity of this operation is « N »
• Or is O(n)
#Devoxx #ListJ9 @JosePaumard
Notation O(N)
• This notation means that:
 if we multiply the amount of elements to be processed by 2
 then the number of operations will also be multiplied by 2
#Devoxx #ListJ9 @JosePaumard
Notation O(N)
• The complexity of an algorithm is given by O(f(n))
• Example: f(n) = n2
#Devoxx #ListJ9 @JosePaumard
Notation O(N)
• The complexity of an algorithm is given by O(f(n))
• Example: f(n) = n2
• In fact, it means that the exact number of operations is
f(n) = an2 + bn + g
• And when n reaches a given value
f(n) ~ n2
#Devoxx #ListJ9 @JosePaumard
Notation O(N)
• All right, but processing data is not anly about maths
• In our applications, n has a value, the same for a, b
and g…
• And the theory might not apply very well to our use
case
#Devoxx #ListJ9 @JosePaumard
Complexity comparison
log2(n)
1 0
10 3
100 7
1 000 10
1 000 000 20
#Devoxx #ListJ9 @JosePaumard
Complexity comparison
log2(n) n
1 0 1
10 3 10
100 7 100
1 000 10 1 000
1 000 000 20 1 000 000
#Devoxx #ListJ9 @JosePaumard
Complexity comparison
log2(n) n n x log2(n)
1 0 1 0
10 3 10 30
100 7 100 700
1 000 10 1 000 10 000
1 000 000 20 1 000 000 20 000 000
#Devoxx #ListJ9 @JosePaumard
Complexity comparison
log2(n) n n x log2(n) n2
1 0 1 0 1
10 3 10 30 100
100 7 100 700 10 000
1 000 10 1 000 10 000 1 000 000
1 000 000 20 1 000 000 20 000 000 too much!
#Devoxx #ListJ9 @JosePaumard
Complexity comparison
« too much » means that on any CPU, running a
thousand billion of operations will take at least 20mn
• So we need to parallelize this operations of a large
number of CPU (at least a few thousands)
 We need to change our algorithm
 We are not running this on a single JVM
#Devoxx #ListJ9 @JosePaumard
Lists complexity
• On the basic operations
ArrayList LinkedList
add(e) 1
add(index, e) 1
set(index, e) 1
remove(index) 1
iterator() 1
#Devoxx #ListJ9 @JosePaumard
Lists complexity
• On the basic operations
ArrayList LinkedList
add(e) 1 1
add(index, e) 1 N
set(index, e) 1 N
remove(index) 1 N
iterator() 1 1
#Devoxx #ListJ9 @JosePaumard
Lists complexity
• We still must be cautious…
• There are System.arrayCopy() in ArrayList that are
not here in LinkedList
• Is it a g? Or something that grows with n? And how?
#Devoxx #ListJ9 @JosePaumard
Lists complexity
• We still must be cautious…
• Example: if we consider add(index, e), is
System.arrayCopy() more costly than going through
the pointers of the LinkedList?
• Are there any hidden costs that we did not see?
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• There is a standard tool (Java 9) to bench Java code :
JMH
• A benchmark is an annotated class
• Maven can generate a « transformed » JAR
• Then we run this JAR to get the result of the bench
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Here is a « bench » class
@Warmup(iterations=5, time=10, timeUnit=TimeUnit.MILLISECONDS)
@Measurement(iterations=10, time=10, timeUnit=TimeUnit.MILLISECONDS)
@Fork(value=1,
jvmArgsAppend = {"-XX:+UseParallelGC", "-Xms3g", "-Xmx3g"})
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
public class Bench {
// bench
}
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• POM dependencies, version is 1.15
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version> <!-- 1.15 -->
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• In the class
@Param({"10", "100", "1000"})
private int size;
@Param({LINKED_LIST, ARRAY_LIST})
private String type;
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• In the class
@Setup
public void setup() {
switch(type) {
case ARRAY_LIST :
list = IntStream.range(0, size)
.mapToObj(Integer::toString)
.collect(Collectors.toCollection(
() -> new ArrayList<String>(size)));
break;
// other cases
}
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Simple add operation:
 Can trigger a System.arrayCopy() on ArrayList
 Fast on LinkedList since there is a pointer to the end of the
list
@Benchmark
public boolean simpleAdd() {
return list.add("one more");
}
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Simple add with index:
 Triggers at least one System.arrayCopy() one ArrayList
 Slower on LinkedList since half of the list must be visited
@Benchmark
public boolean simpleAdd() {
list.add(size / 2, "one more");
return true;
}
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Results for Simple Add
LinkedList ArrayList Big ArrayList
10 5,3 ns 3,6 ns 3,6 ns
100 5,3 ns 3,6 ns 3,7 ns
1 000 5,3 ns 3,7 ns 3,7 ns
1 000 000 5,5 ns 3,7 ns 3,7 ns
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Index Read :
 Read operation in the middle of the list
 We expect the worst performance for LinkedList
@Benchmark
public boolean indexRead() {
return list.get(size / 2);
}
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Index Set:
 Write operation in the middle of the list
 We also expect the worst performance for LinkedList
@Benchmark
public boolean indexSet() {
return list.set(size / 2, "one more");
}
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Results for Index Read
LinkedList ArrayList
10 5,5 ns 2,8 ns
100 37,9 ns 2,8 ns
1 000 596 ns 2,8 ns
1 000 000 3,4 ms 2,8 ns
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Results for Index Set
LinkedList ArrayList
10 5,5 ns 3,4 ns
100 36,0 ns 3,5 ns
1 000 602 ns 3,5 ns
1 000 000 3,4 ms 3,5 ns
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Iteration :
 Let us iterate over the whole list
 1st pattern: iterator
@Benchmark
public long iterate() {
long sum = 0;
for (String s : list) {
sum += s.length();
}
return sum;
}
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Iteration :
 Let us iterate over the whole list
 2nd pattern: stream
@Benchmark
public long streamSum() {
return list.stream()
.mapToLong(String::length)
.sum();
}
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Results for Iterate
LinkedList ArrayList
10 14,7 ns 11,6 ns
100 127 ns 84,3 ns
1 000 2,07 ms 895 ns
1 000 000 6,2 ms 3,3 ms
#Devoxx #ListJ9 @JosePaumard
Benchmarks!
• Results for Stream
LinkedList ArrayList
10 33 ns 64 ns
100 174 ns 440 ns
1 000 1,57 ms 3,6 ms
1 000 000 6,1 ms 4,8 ms
#Devoxx #ListJ9 @JosePaumard
removeIf() and sort()
• Let us check the code
#Devoxx #ListJ9 @JosePaumard
First conclusion
• The overhead of the System.arrayCopy() is not that
bad
 It can be avoided in the case of growing lists
• That been said, there is still an unexpected
performance difference, that we need to explain
#Devoxx #ListJ9 @JosePaumard
CPU architecture
• The multicores CPU work in a special way…
• Between the main memory and the ALU (arithmetic &
logic computation) there are at least 3 levels of cache,
and registers
#Devoxx #ListJ9 @JosePaumard
CPU architecture
Core 1
Access to the registers
< 1ns
#Devoxx #ListJ9 @JosePaumard
CPU architecture
Core 1
L1
Access to the registers
< 1ns
Access time ~1ns
32kB data / code
#Devoxx #ListJ9 @JosePaumard
CPU architecture
Core 1
L1
Access to the registers
< 1ns
Access time ~1ns
32kB data / code
L2
Access time ~3ns
256 kB
#Devoxx #ListJ9 @JosePaumard
CPU architecture
Core 1
L1
L2
Core N
L1
L2
#Devoxx #ListJ9 @JosePaumard
CPU architecture
Core 1
L1
L2
L3 (~12ns)
Core N
L1
L2
#Devoxx #ListJ9 @JosePaumard
CPU architecture
C 1
L1
L2
L3
C N
L1
L2
C 1
L1
L2
L3
C N
L1
L2
#Devoxx #ListJ9 @JosePaumard
CPU architecture
C 1
L1
L2
L3
QPI
C N
L1
L2
C 1
L1
L2
L3
QPI
C N
L1
L2
~40 ns
#Devoxx #ListJ9 @JosePaumard
CPU architecture
C 1
L1
L2
L3
QPI
DRAM (~65 ns)
C N
L1
L2
C 1
L1
L2
L3
QPI
C N
L1
L2
~40 ns
#Devoxx #ListJ9 @JosePaumard
So…
• Writing good algorithms is not enough…
• They also need to be adapted to this structure!
#Devoxx #ListJ9 @JosePaumard
So…
• Writing good algorithms is not enough…
• They also need to be adapted to this structure!
• What makes a processing fast is its capacity to bring
the processed data in the L1 cache as fast as possible
#Devoxx #ListJ9 @JosePaumard
The ennemy is the cache miss!
• A cache miss occurs when the CPU needs a data that is
not in the L1 cache
• This data has to be fetched somewhere else
• In the worst case: in main memory
• A cache miss is a loss of about 500 instructions
#Devoxx #ListJ9 @JosePaumard
Structure of the L1 cache
• The L1 cache is organized in lines
• Each line is 8 long = 64 bytes
• The data is transfered line by line between the caches
and the main memory
• And here lies a big difference between ArrayList and
LinkedList…
#Devoxx #ListJ9 @JosePaumard
Transferring a list in L1
• The elements of an ArrayList are stored in
contiguous zones of the memory, since it is an array
• Where the nodes of a LinkedList are randomly
spread…
• So transferring an ArrayList in the L1 cache can be 8
times faster than a LinkedList (at least)
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• This phenomenon is called « pointer chasing », and it
can kill performances!
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• Example
int[] tab = {1, 2, 3, 4, 5};
Integer[] tab = {1, 2, 3, 4, 5};
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• Example
int[] tab = {1, 2, 3, 4, 5};
Integer[] tab = {1, 2, 3, 4, 5};
1 2 3 4 5
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• Example
int[] tab = {1, 2, 3, 4, 5};
Integer[] tab = {1, 2, 3, 4, 5};
1 2 3 4 5
    
1
2
4
5
3
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• Example
public class Point {
Integer x, y;
}
List<Point> points = new ArrayList<>();
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• Example
public class Point {
Integer x, y;
}
List<Point> points = new ArrayList<>();





x
y
1
2
#Devoxx #ListJ9 @JosePaumard
• Example
• With such a structure, an algorithm will spend all its
time chasing pointers…
Pointer chasing
public class Point {
Integer x, y;
}
List<Point> points = new ArrayList<>();





x
y
1
2
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• Clearly, the LinkedList structure is not adapted to the
structure of CPU
• It is not a « cache friendly » structure
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• An other example: HashMap
 What is a HashMap? An array of Map.Entry objects
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• An other example: HashMap
 What is a HashMap? An array of Map.Entry objects
key
value
#Devoxx #ListJ9 @JosePaumard
Pointer chasing
• An other example: HashMap
 What is a HashMap? An array of Map.Entry objects
key
value
12
« twelve »
#Devoxx #ListJ9 @JosePaumard
• An other example: HashMap
 What is a HashMap? An array of Map.Entry objects
Pointer chasing
key
value
12
« twelve »



#Devoxx #ListJ9 @JosePaumard
• An other example: HashMap
 What is a HashMap? An array of Map.Entry objects
• The same goes for HashSet…
Pointer chasing
key
value
12
« twelve »



#Devoxx #ListJ9 @JosePaumard
Some more benchmarks
• Results for Iterate
HashSet ArrayList
10 26,2 ns 11,6 ns
100 223 ns 84,3 ns
1 000 3,4 ms 895 ns
1 000 000 11 ms 3,3 ms
#Devoxx #ListJ9 @JosePaumard
• In our bench, the LinkedList is built like that:
• It means that out Node elements are still in contiguous
places in memory…
A closer look at our bench
list = IntStream.range(0, size)
.mapToObj(Integer::toString)
.collect(toCollection(LinkedList::new));
#Devoxx #ListJ9 @JosePaumard
• What about building our LinkedList like that:
• No more contiguous nodes…
A closer look at our bench
list = IntStream.range(0, size)
.mapToObj(i -> IntStream.range(i, i + 100)
.mapToObj(Integer::toString)
.collect(toList())
)
.map(l -> l.get(0))
.collect(toCollection(LinkedList::new));
#Devoxx #ListJ9 @JosePaumard
A closer look at our bench
• Results for Indexed Iterate
LinkedList Sparse LinkedList
10 14,7 ns 16,7 ns
100 127 ns 393 ns
1 000 2,07 ms 11 ms
1 000 000 6,2 ms 18 ms
#Devoxx #ListJ9 @JosePaumard
A closer look at our bench
• Results for Indexed Read
LinkedList Sparse LinkedList
10 5,5 ns 5,4 ns
100 37,9 ns 69 ns
1 000 596 ns 2,0 ms
1 000 000 3,4 ms 15,3 ms
#Devoxx #ListJ9 @JosePaumard
A closer look at our bench
• Results for Indexed Set
LinkedList Sparse LinkedList
10 5,5 ns 6,2 ns
100 36,0 ns 83,7 ns
1 000 602 ns 2,0 ms
1 000 000 3,4 ms 14,0 ms
#Devoxx #ListJ9 @JosePaumard
Any other way?
• In a not-so-distant future: List<int> !
 Project Valhalla:
http://mail.openjdk.java.net/pipermail/valhalla-spec-experts/
• Motto:
Codes like a class, works like an int!
#Devoxx #ListJ9 @JosePaumard
Any other way?
• In the much closer present:
 Eclipse Collections (prev. GS Collections)
 HPPC
 Koloboke
 Trove
http://java-performance.info/hashmap-overview-jdk-fastutil-
goldman-sachs-hppc-koloboke-trove-january-2015/
#Devoxx #ListJ9 @JosePaumard
A list without object?
• Is it possible to create implementations of Set / List /
Map without any pointer chasing?
#Devoxx #ListJ9 @JosePaumard
A list without object?
• Construire des implémentations de Set / List / Map
sans pointer chasing ?
• Pointer chasing comes from objects… Can we get rid of
objects in those implementations?
#Devoxx
José Paumard
Factory methods for Collections in Java 9
Live coding: unexpected implementations of
lists, sets, maps
#Devoxx
José Paumard
#Devoxx #ListJ9 @JosePaumard
So where do we want to go?
• Starting point: Java 9!
• Question: how to create a list with objects in it
• Answer: not easily done in Java 8…
#Devoxx #ListJ9 @JosePaumard
A glimpse at Java 9
• Until Java 8: (mustache syntax)
• And if you want the immutable version, you need to
create in two steps…
Map<Integer, String> map = new HashMap<Integer, String>() {{
put(1, "one") ;
put(2, "two") ;
put(3, "three") ;
}} ;
#Devoxx #ListJ9 @JosePaumard
A glimpse at Java 9
• New patterns in Java 9 for lists and sets:
 The implementations are immutables
 Null elements are not allowed (NPE)
 The Set throws an IllegalArgumentException in case of a
double
 Serializable…
List<Integer> list = List.of(1, 2, 3) ;
Set<Integer> set = Set.of(1, 2, 3) ;
#Devoxx #ListJ9 @JosePaumard
A glimpse at Java 9
• New patterns in Java 9 for lists and sets:
• But they are also:
 Randomly iterable
 And with optimized implementations
List<Integer> list = List.of(1, 2, 3) ;
Set<Integer> set = Set.of(1, 2, 3) ;
#Devoxx #ListJ9 @JosePaumard
A glimpse at Java 9
• Optimized implementations:
public static List<E> of(E e1);
public static List<E> of(E e1, E e2);
public static List<E> of(E e1, E e2, E e3);
public static List<E> of(E e1, E e2, E e3, E e4);
...
public static List<E> of(E... e);
#Devoxx #ListJ9 @JosePaumard
A glimpse at Java 9
• In the case of Map
public static Map<K, V> of(K key1, V value1);
public static Map<K, V> of(K key1, V value1, K key2, V value2);
...
public static Map<K, V> of(K... K, V... v);
#Devoxx #ListJ9 @JosePaumard
A glimpse at Java 9
• In the case of Map
 ofEntries() throws an exception in the case of a double key
public static Map<K, V> of(K key1, V value1);
public static Map<K, V> of(K key1, V value1, K key2, V value2);
...
public static Map<K, V> of(K... K, V... v);
public static Entry<K, V> of(K key, V value);
public static Map<K, V> ofEntries(Entry... e);
#Devoxx #ListJ9 @JosePaumard
A glimpse at Java 9
Map<String, TokenType> tokens =
Map.ofEntries(
entry("for", KEYWORD),
entry("while", KEYWORD),
entry("do", KEYWORD),
entry("break", KEYWORD),
entry(":", COLON),
entry("+", PLUS),
entry("--‐", MINUS),
entry(">", GREATER),
entry("<", LESS),
entry(":", PAAMAYIM_NEKUDOTAYIM),
entry("(", LPAREN),
entry(")", RPAREN)
); © Stuart Mark
#Devoxx #ListJ9 @JosePaumard
A glimpse at Java 9
Map<String, TokenType> tokens =
Map.ofEntries(
entry("for", KEYWORD),
entry("while", KEYWORD),
entry("do", KEYWORD),
entry("break", KEYWORD),
entry(":", COLON),
entry("+", PLUS),
entry("--‐", MINUS),
entry(">", GREATER),
entry("<", LESS),
entry(":", PAAMAYIM_NEKUDOTAYIM),
entry("(", LPAREN),
entry(")", RPAREN)
); © Stuart Mark
#Devoxx #ListJ9 @JosePaumard
What do we want to do?
• Question: how can we build an optimized
implementation of a list with 1 or 2 elements?
• Set, List and Map (and Map.Entry)
• Of course we want to minimize pointer chasing
#Devoxx
Don’t worry, they’ll be back
And bullet points too
#Devoxx #ListJ9 @JosePaumard
Some more bench
• Results for indexed read
ArrayList SingletonList TwoElementList
1 3,5 ns 2,7 ns
2 2,9 ns 2,6 ns
#Devoxx #ListJ9 @JosePaumard
Some more bench
• Results for Iterate
ArrayList SingletonList TwoElementList
1 4,7 ns 2,3 ns
2 6,5 ns 3,4 ns
#Devoxx #ListJ9 @JosePaumard
Some more bench
• Results for Iterate
HashSet SingletonSet TwoElementSet
1 7,3 ns 2,3 ns
2 9,5 ns 3,5 ns
#Devoxx #ListJ9 @JosePaumard
Conclusion
• By Stuart Marks:
#Devoxx #ListJ9 @JosePaumard
Conclusion
• Many patterns from the GoF can be implemented with
lambdas
• We saw it for the template method
• And used it for lists, sets and maps…
 But should be avoided!
• Avoiding pointer chasing = best performances!
#Devoxx
José Paumard
#Devoxx
Thank you!
José Paumard

More Related Content

PPTX
Pandas csv
PDF
Java 8, Streams & Collectors, patterns, performances and parallelization
PDF
Function arguments In Python
PPTX
Php functions
PPTX
Python: Basic Inheritance
PPTX
PHP Form Validation Technique
PDF
If You Think You Can Stay Away from Functional Programming, You Are Wrong
PPTX
USER DEFINE FUNCTIONS IN PYTHON
Pandas csv
Java 8, Streams & Collectors, patterns, performances and parallelization
Function arguments In Python
Php functions
Python: Basic Inheritance
PHP Form Validation Technique
If You Think You Can Stay Away from Functional Programming, You Are Wrong
USER DEFINE FUNCTIONS IN PYTHON

What's hot (20)

PPTX
PHP Functions & Arrays
PDF
Django Tutorial | Django Web Development With Python | Django Training and Ce...
PPTX
PPT
OOP V3.1
PDF
Constructor and Destructor
PPSX
python Function
PDF
JavaScript - Chapter 11 - Events
PDF
Function lecture
PDF
Php tutorial(w3schools)
PDF
Python programming : Strings
PPTX
class and objects
KEY
Introduction to Django
PPT
08 c++ Operator Overloading.ppt
PDF
systems programming lab programs in c
PPTX
This pointer
PPTX
Built in function
PPT
JavaScript
PDF
Jpa 잘 (하는 척) 하기
PDF
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
PHP Functions & Arrays
Django Tutorial | Django Web Development With Python | Django Training and Ce...
OOP V3.1
Constructor and Destructor
python Function
JavaScript - Chapter 11 - Events
Function lecture
Php tutorial(w3schools)
Python programming : Strings
class and objects
Introduction to Django
08 c++ Operator Overloading.ppt
systems programming lab programs in c
This pointer
Built in function
JavaScript
Jpa 잘 (하는 척) 하기
Python Functions Tutorial | Working With Functions In Python | Python Trainin...
Ad

Viewers also liked (20)

PDF
Free your lambdas
PDF
API Asynchrones en Java 8
PDF
Les Streams sont parmi nous
PDF
50 new things we can do with Java 8
PDF
50 nouvelles choses que l'on peut faire avec Java 8
PDF
Java 8 Stream API and RxJava Comparison
PDF
ArrayList et LinkedList sont dans un bateau
PDF
Java SE 8 for Java EE developers
PDF
Autumn collection JavaOne 2014
PDF
Java 8-streams-collectors-patterns
PDF
50 new things you can do with java 8
PPTX
JFokus 50 new things with java 8
PDF
Going reactive in java
PDF
Déploiement d'une application Java EE dans Azure
PDF
JDK 8, lambdas, streams, collectors - Bretagne Tour
PDF
50 nouvelles choses que l'on peut faire en Java 8
PDF
Java 8 Streams and Rx Java Comparison
PPTX
Openmelodie nouvelles fonctionnalités
PPTX
Open melodie concepts
PDF
Autumn collections : from iterable to lambdas, streams and collectors
Free your lambdas
API Asynchrones en Java 8
Les Streams sont parmi nous
50 new things we can do with Java 8
50 nouvelles choses que l'on peut faire avec Java 8
Java 8 Stream API and RxJava Comparison
ArrayList et LinkedList sont dans un bateau
Java SE 8 for Java EE developers
Autumn collection JavaOne 2014
Java 8-streams-collectors-patterns
50 new things you can do with java 8
JFokus 50 new things with java 8
Going reactive in java
Déploiement d'une application Java EE dans Azure
JDK 8, lambdas, streams, collectors - Bretagne Tour
50 nouvelles choses que l'on peut faire en Java 8
Java 8 Streams and Rx Java Comparison
Openmelodie nouvelles fonctionnalités
Open melodie concepts
Autumn collections : from iterable to lambdas, streams and collectors
Ad

Similar to Linked to ArrayList: the full story (20)

PPTX
Lecture 2 - Linear Data Structures & Implementation.pptx
PPT
PPT
PPTX
U-III-part-1.pptxpart 1 of Java and hardware coding questions are answered
PPTX
LinkedList vs Arraylist- an in depth look at java.util.LinkedList
PPTX
Lecture ............ 3 - Linked Lists.pptx
PPTX
Linked lists a
PPT
List data structure
PPT
List Data Structure
PPT
LINKEDb2bb22bb3b3b3b3n3_LIST_UKL_1-2.ppt
PPT
cse220lec4.pptnnnnnnnnnnnnnnnnnnnnnnnnnnn
PPTX
Data structures and Algorithm analysis_Lecture 2.pptx
PPTX
Collections Array list
PPTX
Doubly linked list (animated)
PDF
Lab02kdfshdfgajhdfgajhdfgajhdfgjhadgfasjhdgfjhasdgfjh.pdf
PPTX
Data structures in c#
PPT
03_LinkedLists_091.ppt
PPT
Lecture 2 - Linear Data Structures & Implementation.pptx
U-III-part-1.pptxpart 1 of Java and hardware coding questions are answered
LinkedList vs Arraylist- an in depth look at java.util.LinkedList
Lecture ............ 3 - Linked Lists.pptx
Linked lists a
List data structure
List Data Structure
LINKEDb2bb22bb3b3b3b3n3_LIST_UKL_1-2.ppt
cse220lec4.pptnnnnnnnnnnnnnnnnnnnnnnnnnnn
Data structures and Algorithm analysis_Lecture 2.pptx
Collections Array list
Doubly linked list (animated)
Lab02kdfshdfgajhdfgajhdfgajhdfgjhadgfasjhdgfjhasdgfjh.pdf
Data structures in c#
03_LinkedLists_091.ppt

More from José Paumard (20)

PDF
Loom Virtual Threads in the JDK 19
PDF
From Java 11 to 17 and beyond.pdf
PDF
The Future of Java: Records, Sealed Classes and Pattern Matching
PDF
Deep Dive Java 17 Devoxx UK
PDF
Designing functional and fluent API: application to some GoF patterns
PDF
The Sincerest Form of Flattery
PPTX
The Sincerest Form of Flattery
PDF
Designing functional and fluent API: example of the Visitor Pattern
PDF
Construire son JDK en 10 étapes
PDF
Java Keeps Throttling Up!
PDF
Lambdas and Streams Master Class Part 2
PDF
Lambda and Stream Master class - part 1
PDF
Asynchronous Systems with Fn Flow
PDF
Java Full Throttle
PDF
JAX-RS and CDI Bike the (Reactive) Bridge
PDF
Collectors in the Wild
PDF
Streams in the wild
PDF
JAX RS and CDI bike the reactive bridge
PDF
Free your lambdas
PDF
L'API Collector dans tous ses états
Loom Virtual Threads in the JDK 19
From Java 11 to 17 and beyond.pdf
The Future of Java: Records, Sealed Classes and Pattern Matching
Deep Dive Java 17 Devoxx UK
Designing functional and fluent API: application to some GoF patterns
The Sincerest Form of Flattery
The Sincerest Form of Flattery
Designing functional and fluent API: example of the Visitor Pattern
Construire son JDK en 10 étapes
Java Keeps Throttling Up!
Lambdas and Streams Master Class Part 2
Lambda and Stream Master class - part 1
Asynchronous Systems with Fn Flow
Java Full Throttle
JAX-RS and CDI Bike the (Reactive) Bridge
Collectors in the Wild
Streams in the wild
JAX RS and CDI bike the reactive bridge
Free your lambdas
L'API Collector dans tous ses états

Recently uploaded (20)

PDF
RMMM.pdf make it easy to upload and study
PPTX
Cell Structure & Organelles in detailed.
PDF
Computing-Curriculum for Schools in Ghana
PDF
Classroom Observation Tools for Teachers
PDF
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
PDF
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
PDF
O7-L3 Supply Chain Operations - ICLT Program
PPTX
master seminar digital applications in india
PPTX
Lesson notes of climatology university.
PDF
GENETICS IN BIOLOGY IN SECONDARY LEVEL FORM 3
PDF
Module 4: Burden of Disease Tutorial Slides S2 2025
PPTX
GDM (1) (1).pptx small presentation for students
PPTX
human mycosis Human fungal infections are called human mycosis..pptx
PDF
STATICS OF THE RIGID BODIES Hibbelers.pdf
PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PPTX
Pharma ospi slides which help in ospi learning
PPTX
Final Presentation General Medicine 03-08-2024.pptx
PPTX
PPT- ENG7_QUARTER1_LESSON1_WEEK1. IMAGERY -DESCRIPTIONS pptx.pptx
PDF
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
PDF
Abdominal Access Techniques with Prof. Dr. R K Mishra
RMMM.pdf make it easy to upload and study
Cell Structure & Organelles in detailed.
Computing-Curriculum for Schools in Ghana
Classroom Observation Tools for Teachers
The Lost Whites of Pakistan by Jahanzaib Mughal.pdf
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
O7-L3 Supply Chain Operations - ICLT Program
master seminar digital applications in india
Lesson notes of climatology university.
GENETICS IN BIOLOGY IN SECONDARY LEVEL FORM 3
Module 4: Burden of Disease Tutorial Slides S2 2025
GDM (1) (1).pptx small presentation for students
human mycosis Human fungal infections are called human mycosis..pptx
STATICS OF THE RIGID BODIES Hibbelers.pdf
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
Pharma ospi slides which help in ospi learning
Final Presentation General Medicine 03-08-2024.pptx
PPT- ENG7_QUARTER1_LESSON1_WEEK1. IMAGERY -DESCRIPTIONS pptx.pptx
3rd Neelam Sanjeevareddy Memorial Lecture.pdf
Abdominal Access Techniques with Prof. Dr. R K Mishra

Linked to ArrayList: the full story

  • 1. #Devoxx LinkedList to ArrayList The Full Story! José Paumard
  • 2. #Devoxx #ListJ9 @JosePaumard It all begin… • November 22nd 2015 by a tweet
  • 3. #Devoxx #ListJ9 @JosePaumard It all begin… • Then the discussion started
  • 4. #Devoxx #ListJ9 @JosePaumard It all begin… • And about 30 tweets later:
  • 5. #Devoxx #ListJ9 @JosePaumard And did not ended there! • And around midnight, 7th nov. 2016: • Since this is the subject of this Uni, we will take more time…
  • 7. #Devoxx #ListJ9 @JosePaumard Questions ? #ListJ9 Questions? #ListJ9
  • 8. #Devoxx #ListJ9 @JosePaumard • This discussion ArrayList vs LinkedList is no troll…  Even if it looks like one! • The question is : Is one of these implementations better than the other? • And there is an answer to this question! And the conclusion is…
  • 9. #Devoxx #ListJ9 @JosePaumard And the conclusion is… • To fully understand this answer, we need to understand many other things
  • 10. #Devoxx #ListJ9 @JosePaumard And the conclusion is… • To fully understand this answer, we need to understand many other things • And once we have answered it (almost) fully , many other questions will arise!
  • 11. #Devoxx #ListJ9 @JosePaumard 1st part • Algorithms • Complexity • Implementation • CPU architecture • « cache friendly » • Slides, bullet points…
  • 12. #Devoxx #ListJ9 @JosePaumard 2nd part • Implementation of Set, List et Map (with a surprise!) • Live coding! • Some more slides but not that many  But don’t worry, still bullet points
  • 13. #Devoxx #ListJ9 @JosePaumard Where to begin? • In fact there are several ways to begin…
  • 14. #Devoxx #ListJ9 @JosePaumard Where to begin? • In fact there are several ways to begin… • Algorithms!
  • 15. #Devoxx #ListJ9 @JosePaumard Where to begin? • In fact there are several ways to begin… • Algorithms! • Implementation vs CPU architecture
  • 16. #Devoxx #ListJ9 @JosePaumard Where to begin? • In fact there are several ways to begin… • Algorithms! • Implementation vs CPU architecture • Use cases
  • 17. #Devoxx #ListJ9 @JosePaumard What do we know? 1) ArrayList is built on an array 2) LinkedList is built on a linked list And we have results on this
  • 18. #Devoxx #ListJ9 @JosePaumard Approach • Take a close look at the basic operations on lists • Create / modify:  Add an element at the end of at the beginning of a list  Removing an element by its index  Removing an element  The contains() method  The removeIf() and sort() methods
  • 19. #Devoxx #ListJ9 @JosePaumard Approach • Take a close look at the basic operations on lists • Add: List<String> list = ... list.add("one"); // add list.add(12, "one"); // insert
  • 20. #Devoxx #ListJ9 @JosePaumard Approach • Take a close look at the basic operations on lists • Remove: List<String> list = ... list.remove("one"); // remove list.remove(12); // remove by index
  • 21. #Devoxx #ListJ9 @JosePaumard Approach • Take a close look at the basic operations on lists • Sort / removeIf: List<String> list = ... list.sort(comparingBy(String::length)); // sort list.removeIf(s -> s.length() > 10); // remove if
  • 22. #Devoxx #ListJ9 @JosePaumard Approach • Take a close look at the basic operations on lists • Read operations:  Iterate  Read an element with its index  Building a Stream
  • 23. #Devoxx #ListJ9 @JosePaumard Approach • Take a close look at the basis operations on lists • Read operations: List<String> list = ... list.forEach(System.out::println); // list traversal list.get(12); // access by index list.stream(); // stream creation
  • 24. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Access to the nth element: almost free • Adding an element: almost free, but… • Insertion: shift the elements to the right • Deletion: shift the elements to the left
  • 25. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Access to the nth element: almost free n
  • 26. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Adding an element: almost free, but… private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); elementData = Arrays.copyOf(elementData, newCapacity); }
  • 27. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Adding an element: almost free, but… • Sometimes the array has to be enlarge • But we can fix the size of the array when we build it
  • 28. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Adding an element: almost free, but… • Sometimes the array has to be enlarge • Bytheway growing a HashSet is much more expensive…
  • 29. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Insertion n, one
  • 30. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Insertion public void add(int index, E element) { System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
  • 31. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Insertion one
  • 32. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Suppression n X
  • 33. #Devoxx #ListJ9 @JosePaumard ArrayList • Built on an array • Suppression public E remove(int index) { E oldValue = elementData(index); System.arraycopy(elementData, index+1, elementData, index, numMoved); return oldValue; }
  • 34. #Devoxx #ListJ9 @JosePaumard ArrayList • (Very) Early conclusion • Accessing an element is fast! • Adding is fast, if there is no overflow • Random insert / delete: overhead to handle the « holes »
  • 35. #Devoxx #ListJ9 @JosePaumard LinkedList • Built on a double linked list • Access to the nth element • Adding an element at the end of the list • Insertion • Deletion
  • 36. #Devoxx #ListJ9 @JosePaumard LinkedList • Base structure next prev item Node next prev item Node next prev item Node first last
  • 37. #Devoxx #ListJ9 @JosePaumard LinkedList • Built on a double linked list • Access to the nth element: run through all the elements • Adding: free, just a modification of pointers • Insertion: free, just a modification of pointers • Suppression: free, just a modification of pointers
  • 38. #Devoxx #ListJ9 @JosePaumard LinkedList • Access to the nth element Node<E> node(int index) { if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } // same for last }
  • 39. #Devoxx #ListJ9 @JosePaumard LinkedList • Access to the nth element: one has to visit all the elements and count them, until the nth is found • We say that the complexity of this operation is « N » • Or is O(n)
  • 40. #Devoxx #ListJ9 @JosePaumard Notation O(N) • This notation means that:  if we multiply the amount of elements to be processed by 2  then the number of operations will also be multiplied by 2
  • 41. #Devoxx #ListJ9 @JosePaumard Notation O(N) • The complexity of an algorithm is given by O(f(n)) • Example: f(n) = n2
  • 42. #Devoxx #ListJ9 @JosePaumard Notation O(N) • The complexity of an algorithm is given by O(f(n)) • Example: f(n) = n2 • In fact, it means that the exact number of operations is f(n) = an2 + bn + g • And when n reaches a given value f(n) ~ n2
  • 43. #Devoxx #ListJ9 @JosePaumard Notation O(N) • All right, but processing data is not anly about maths • In our applications, n has a value, the same for a, b and g… • And the theory might not apply very well to our use case
  • 44. #Devoxx #ListJ9 @JosePaumard Complexity comparison log2(n) 1 0 10 3 100 7 1 000 10 1 000 000 20
  • 45. #Devoxx #ListJ9 @JosePaumard Complexity comparison log2(n) n 1 0 1 10 3 10 100 7 100 1 000 10 1 000 1 000 000 20 1 000 000
  • 46. #Devoxx #ListJ9 @JosePaumard Complexity comparison log2(n) n n x log2(n) 1 0 1 0 10 3 10 30 100 7 100 700 1 000 10 1 000 10 000 1 000 000 20 1 000 000 20 000 000
  • 47. #Devoxx #ListJ9 @JosePaumard Complexity comparison log2(n) n n x log2(n) n2 1 0 1 0 1 10 3 10 30 100 100 7 100 700 10 000 1 000 10 1 000 10 000 1 000 000 1 000 000 20 1 000 000 20 000 000 too much!
  • 48. #Devoxx #ListJ9 @JosePaumard Complexity comparison « too much » means that on any CPU, running a thousand billion of operations will take at least 20mn • So we need to parallelize this operations of a large number of CPU (at least a few thousands)  We need to change our algorithm  We are not running this on a single JVM
  • 49. #Devoxx #ListJ9 @JosePaumard Lists complexity • On the basic operations ArrayList LinkedList add(e) 1 add(index, e) 1 set(index, e) 1 remove(index) 1 iterator() 1
  • 50. #Devoxx #ListJ9 @JosePaumard Lists complexity • On the basic operations ArrayList LinkedList add(e) 1 1 add(index, e) 1 N set(index, e) 1 N remove(index) 1 N iterator() 1 1
  • 51. #Devoxx #ListJ9 @JosePaumard Lists complexity • We still must be cautious… • There are System.arrayCopy() in ArrayList that are not here in LinkedList • Is it a g? Or something that grows with n? And how?
  • 52. #Devoxx #ListJ9 @JosePaumard Lists complexity • We still must be cautious… • Example: if we consider add(index, e), is System.arrayCopy() more costly than going through the pointers of the LinkedList? • Are there any hidden costs that we did not see?
  • 53. #Devoxx #ListJ9 @JosePaumard Benchmarks! • There is a standard tool (Java 9) to bench Java code : JMH • A benchmark is an annotated class • Maven can generate a « transformed » JAR • Then we run this JAR to get the result of the bench
  • 54. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Here is a « bench » class @Warmup(iterations=5, time=10, timeUnit=TimeUnit.MILLISECONDS) @Measurement(iterations=10, time=10, timeUnit=TimeUnit.MILLISECONDS) @Fork(value=1, jvmArgsAppend = {"-XX:+UseParallelGC", "-Xms3g", "-Xmx3g"}) @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Benchmark) public class Bench { // bench }
  • 55. #Devoxx #ListJ9 @JosePaumard Benchmarks! • POM dependencies, version is 1.15 <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>${jmh.version}</version> <!-- 1.15 --> </dependency> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-generator-annprocess</artifactId> <version>${jmh.version}</version> <scope>provided</scope> </dependency>
  • 56. #Devoxx #ListJ9 @JosePaumard Benchmarks! • In the class @Param({"10", "100", "1000"}) private int size; @Param({LINKED_LIST, ARRAY_LIST}) private String type;
  • 57. #Devoxx #ListJ9 @JosePaumard Benchmarks! • In the class @Setup public void setup() { switch(type) { case ARRAY_LIST : list = IntStream.range(0, size) .mapToObj(Integer::toString) .collect(Collectors.toCollection( () -> new ArrayList<String>(size))); break; // other cases }
  • 58. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Simple add operation:  Can trigger a System.arrayCopy() on ArrayList  Fast on LinkedList since there is a pointer to the end of the list @Benchmark public boolean simpleAdd() { return list.add("one more"); }
  • 59. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Simple add with index:  Triggers at least one System.arrayCopy() one ArrayList  Slower on LinkedList since half of the list must be visited @Benchmark public boolean simpleAdd() { list.add(size / 2, "one more"); return true; }
  • 60. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Results for Simple Add LinkedList ArrayList Big ArrayList 10 5,3 ns 3,6 ns 3,6 ns 100 5,3 ns 3,6 ns 3,7 ns 1 000 5,3 ns 3,7 ns 3,7 ns 1 000 000 5,5 ns 3,7 ns 3,7 ns
  • 61. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Index Read :  Read operation in the middle of the list  We expect the worst performance for LinkedList @Benchmark public boolean indexRead() { return list.get(size / 2); }
  • 62. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Index Set:  Write operation in the middle of the list  We also expect the worst performance for LinkedList @Benchmark public boolean indexSet() { return list.set(size / 2, "one more"); }
  • 63. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Results for Index Read LinkedList ArrayList 10 5,5 ns 2,8 ns 100 37,9 ns 2,8 ns 1 000 596 ns 2,8 ns 1 000 000 3,4 ms 2,8 ns
  • 64. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Results for Index Set LinkedList ArrayList 10 5,5 ns 3,4 ns 100 36,0 ns 3,5 ns 1 000 602 ns 3,5 ns 1 000 000 3,4 ms 3,5 ns
  • 65. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Iteration :  Let us iterate over the whole list  1st pattern: iterator @Benchmark public long iterate() { long sum = 0; for (String s : list) { sum += s.length(); } return sum; }
  • 66. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Iteration :  Let us iterate over the whole list  2nd pattern: stream @Benchmark public long streamSum() { return list.stream() .mapToLong(String::length) .sum(); }
  • 67. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Results for Iterate LinkedList ArrayList 10 14,7 ns 11,6 ns 100 127 ns 84,3 ns 1 000 2,07 ms 895 ns 1 000 000 6,2 ms 3,3 ms
  • 68. #Devoxx #ListJ9 @JosePaumard Benchmarks! • Results for Stream LinkedList ArrayList 10 33 ns 64 ns 100 174 ns 440 ns 1 000 1,57 ms 3,6 ms 1 000 000 6,1 ms 4,8 ms
  • 69. #Devoxx #ListJ9 @JosePaumard removeIf() and sort() • Let us check the code
  • 70. #Devoxx #ListJ9 @JosePaumard First conclusion • The overhead of the System.arrayCopy() is not that bad  It can be avoided in the case of growing lists • That been said, there is still an unexpected performance difference, that we need to explain
  • 71. #Devoxx #ListJ9 @JosePaumard CPU architecture • The multicores CPU work in a special way… • Between the main memory and the ALU (arithmetic & logic computation) there are at least 3 levels of cache, and registers
  • 72. #Devoxx #ListJ9 @JosePaumard CPU architecture Core 1 Access to the registers < 1ns
  • 73. #Devoxx #ListJ9 @JosePaumard CPU architecture Core 1 L1 Access to the registers < 1ns Access time ~1ns 32kB data / code
  • 74. #Devoxx #ListJ9 @JosePaumard CPU architecture Core 1 L1 Access to the registers < 1ns Access time ~1ns 32kB data / code L2 Access time ~3ns 256 kB
  • 75. #Devoxx #ListJ9 @JosePaumard CPU architecture Core 1 L1 L2 Core N L1 L2
  • 76. #Devoxx #ListJ9 @JosePaumard CPU architecture Core 1 L1 L2 L3 (~12ns) Core N L1 L2
  • 77. #Devoxx #ListJ9 @JosePaumard CPU architecture C 1 L1 L2 L3 C N L1 L2 C 1 L1 L2 L3 C N L1 L2
  • 78. #Devoxx #ListJ9 @JosePaumard CPU architecture C 1 L1 L2 L3 QPI C N L1 L2 C 1 L1 L2 L3 QPI C N L1 L2 ~40 ns
  • 79. #Devoxx #ListJ9 @JosePaumard CPU architecture C 1 L1 L2 L3 QPI DRAM (~65 ns) C N L1 L2 C 1 L1 L2 L3 QPI C N L1 L2 ~40 ns
  • 80. #Devoxx #ListJ9 @JosePaumard So… • Writing good algorithms is not enough… • They also need to be adapted to this structure!
  • 81. #Devoxx #ListJ9 @JosePaumard So… • Writing good algorithms is not enough… • They also need to be adapted to this structure! • What makes a processing fast is its capacity to bring the processed data in the L1 cache as fast as possible
  • 82. #Devoxx #ListJ9 @JosePaumard The ennemy is the cache miss! • A cache miss occurs when the CPU needs a data that is not in the L1 cache • This data has to be fetched somewhere else • In the worst case: in main memory • A cache miss is a loss of about 500 instructions
  • 83. #Devoxx #ListJ9 @JosePaumard Structure of the L1 cache • The L1 cache is organized in lines • Each line is 8 long = 64 bytes • The data is transfered line by line between the caches and the main memory • And here lies a big difference between ArrayList and LinkedList…
  • 84. #Devoxx #ListJ9 @JosePaumard Transferring a list in L1 • The elements of an ArrayList are stored in contiguous zones of the memory, since it is an array • Where the nodes of a LinkedList are randomly spread… • So transferring an ArrayList in the L1 cache can be 8 times faster than a LinkedList (at least)
  • 85. #Devoxx #ListJ9 @JosePaumard Pointer chasing • This phenomenon is called « pointer chasing », and it can kill performances!
  • 86. #Devoxx #ListJ9 @JosePaumard Pointer chasing • Example int[] tab = {1, 2, 3, 4, 5}; Integer[] tab = {1, 2, 3, 4, 5};
  • 87. #Devoxx #ListJ9 @JosePaumard Pointer chasing • Example int[] tab = {1, 2, 3, 4, 5}; Integer[] tab = {1, 2, 3, 4, 5}; 1 2 3 4 5
  • 88. #Devoxx #ListJ9 @JosePaumard Pointer chasing • Example int[] tab = {1, 2, 3, 4, 5}; Integer[] tab = {1, 2, 3, 4, 5}; 1 2 3 4 5      1 2 4 5 3
  • 89. #Devoxx #ListJ9 @JosePaumard Pointer chasing • Example public class Point { Integer x, y; } List<Point> points = new ArrayList<>();
  • 90. #Devoxx #ListJ9 @JosePaumard Pointer chasing • Example public class Point { Integer x, y; } List<Point> points = new ArrayList<>();      x y 1 2
  • 91. #Devoxx #ListJ9 @JosePaumard • Example • With such a structure, an algorithm will spend all its time chasing pointers… Pointer chasing public class Point { Integer x, y; } List<Point> points = new ArrayList<>();      x y 1 2
  • 92. #Devoxx #ListJ9 @JosePaumard Pointer chasing • Clearly, the LinkedList structure is not adapted to the structure of CPU • It is not a « cache friendly » structure
  • 93. #Devoxx #ListJ9 @JosePaumard Pointer chasing • An other example: HashMap  What is a HashMap? An array of Map.Entry objects
  • 94. #Devoxx #ListJ9 @JosePaumard Pointer chasing • An other example: HashMap  What is a HashMap? An array of Map.Entry objects key value
  • 95. #Devoxx #ListJ9 @JosePaumard Pointer chasing • An other example: HashMap  What is a HashMap? An array of Map.Entry objects key value 12 « twelve »
  • 96. #Devoxx #ListJ9 @JosePaumard • An other example: HashMap  What is a HashMap? An array of Map.Entry objects Pointer chasing key value 12 « twelve »   
  • 97. #Devoxx #ListJ9 @JosePaumard • An other example: HashMap  What is a HashMap? An array of Map.Entry objects • The same goes for HashSet… Pointer chasing key value 12 « twelve »   
  • 98. #Devoxx #ListJ9 @JosePaumard Some more benchmarks • Results for Iterate HashSet ArrayList 10 26,2 ns 11,6 ns 100 223 ns 84,3 ns 1 000 3,4 ms 895 ns 1 000 000 11 ms 3,3 ms
  • 99. #Devoxx #ListJ9 @JosePaumard • In our bench, the LinkedList is built like that: • It means that out Node elements are still in contiguous places in memory… A closer look at our bench list = IntStream.range(0, size) .mapToObj(Integer::toString) .collect(toCollection(LinkedList::new));
  • 100. #Devoxx #ListJ9 @JosePaumard • What about building our LinkedList like that: • No more contiguous nodes… A closer look at our bench list = IntStream.range(0, size) .mapToObj(i -> IntStream.range(i, i + 100) .mapToObj(Integer::toString) .collect(toList()) ) .map(l -> l.get(0)) .collect(toCollection(LinkedList::new));
  • 101. #Devoxx #ListJ9 @JosePaumard A closer look at our bench • Results for Indexed Iterate LinkedList Sparse LinkedList 10 14,7 ns 16,7 ns 100 127 ns 393 ns 1 000 2,07 ms 11 ms 1 000 000 6,2 ms 18 ms
  • 102. #Devoxx #ListJ9 @JosePaumard A closer look at our bench • Results for Indexed Read LinkedList Sparse LinkedList 10 5,5 ns 5,4 ns 100 37,9 ns 69 ns 1 000 596 ns 2,0 ms 1 000 000 3,4 ms 15,3 ms
  • 103. #Devoxx #ListJ9 @JosePaumard A closer look at our bench • Results for Indexed Set LinkedList Sparse LinkedList 10 5,5 ns 6,2 ns 100 36,0 ns 83,7 ns 1 000 602 ns 2,0 ms 1 000 000 3,4 ms 14,0 ms
  • 104. #Devoxx #ListJ9 @JosePaumard Any other way? • In a not-so-distant future: List<int> !  Project Valhalla: http://mail.openjdk.java.net/pipermail/valhalla-spec-experts/ • Motto: Codes like a class, works like an int!
  • 105. #Devoxx #ListJ9 @JosePaumard Any other way? • In the much closer present:  Eclipse Collections (prev. GS Collections)  HPPC  Koloboke  Trove http://java-performance.info/hashmap-overview-jdk-fastutil- goldman-sachs-hppc-koloboke-trove-january-2015/
  • 106. #Devoxx #ListJ9 @JosePaumard A list without object? • Is it possible to create implementations of Set / List / Map without any pointer chasing?
  • 107. #Devoxx #ListJ9 @JosePaumard A list without object? • Construire des implémentations de Set / List / Map sans pointer chasing ? • Pointer chasing comes from objects… Can we get rid of objects in those implementations?
  • 108. #Devoxx José Paumard Factory methods for Collections in Java 9 Live coding: unexpected implementations of lists, sets, maps
  • 110. #Devoxx #ListJ9 @JosePaumard So where do we want to go? • Starting point: Java 9! • Question: how to create a list with objects in it • Answer: not easily done in Java 8…
  • 111. #Devoxx #ListJ9 @JosePaumard A glimpse at Java 9 • Until Java 8: (mustache syntax) • And if you want the immutable version, you need to create in two steps… Map<Integer, String> map = new HashMap<Integer, String>() {{ put(1, "one") ; put(2, "two") ; put(3, "three") ; }} ;
  • 112. #Devoxx #ListJ9 @JosePaumard A glimpse at Java 9 • New patterns in Java 9 for lists and sets:  The implementations are immutables  Null elements are not allowed (NPE)  The Set throws an IllegalArgumentException in case of a double  Serializable… List<Integer> list = List.of(1, 2, 3) ; Set<Integer> set = Set.of(1, 2, 3) ;
  • 113. #Devoxx #ListJ9 @JosePaumard A glimpse at Java 9 • New patterns in Java 9 for lists and sets: • But they are also:  Randomly iterable  And with optimized implementations List<Integer> list = List.of(1, 2, 3) ; Set<Integer> set = Set.of(1, 2, 3) ;
  • 114. #Devoxx #ListJ9 @JosePaumard A glimpse at Java 9 • Optimized implementations: public static List<E> of(E e1); public static List<E> of(E e1, E e2); public static List<E> of(E e1, E e2, E e3); public static List<E> of(E e1, E e2, E e3, E e4); ... public static List<E> of(E... e);
  • 115. #Devoxx #ListJ9 @JosePaumard A glimpse at Java 9 • In the case of Map public static Map<K, V> of(K key1, V value1); public static Map<K, V> of(K key1, V value1, K key2, V value2); ... public static Map<K, V> of(K... K, V... v);
  • 116. #Devoxx #ListJ9 @JosePaumard A glimpse at Java 9 • In the case of Map  ofEntries() throws an exception in the case of a double key public static Map<K, V> of(K key1, V value1); public static Map<K, V> of(K key1, V value1, K key2, V value2); ... public static Map<K, V> of(K... K, V... v); public static Entry<K, V> of(K key, V value); public static Map<K, V> ofEntries(Entry... e);
  • 117. #Devoxx #ListJ9 @JosePaumard A glimpse at Java 9 Map<String, TokenType> tokens = Map.ofEntries( entry("for", KEYWORD), entry("while", KEYWORD), entry("do", KEYWORD), entry("break", KEYWORD), entry(":", COLON), entry("+", PLUS), entry("--‐", MINUS), entry(">", GREATER), entry("<", LESS), entry(":", PAAMAYIM_NEKUDOTAYIM), entry("(", LPAREN), entry(")", RPAREN) ); © Stuart Mark
  • 118. #Devoxx #ListJ9 @JosePaumard A glimpse at Java 9 Map<String, TokenType> tokens = Map.ofEntries( entry("for", KEYWORD), entry("while", KEYWORD), entry("do", KEYWORD), entry("break", KEYWORD), entry(":", COLON), entry("+", PLUS), entry("--‐", MINUS), entry(">", GREATER), entry("<", LESS), entry(":", PAAMAYIM_NEKUDOTAYIM), entry("(", LPAREN), entry(")", RPAREN) ); © Stuart Mark
  • 119. #Devoxx #ListJ9 @JosePaumard What do we want to do? • Question: how can we build an optimized implementation of a list with 1 or 2 elements? • Set, List and Map (and Map.Entry) • Of course we want to minimize pointer chasing
  • 120. #Devoxx Don’t worry, they’ll be back And bullet points too
  • 121. #Devoxx #ListJ9 @JosePaumard Some more bench • Results for indexed read ArrayList SingletonList TwoElementList 1 3,5 ns 2,7 ns 2 2,9 ns 2,6 ns
  • 122. #Devoxx #ListJ9 @JosePaumard Some more bench • Results for Iterate ArrayList SingletonList TwoElementList 1 4,7 ns 2,3 ns 2 6,5 ns 3,4 ns
  • 123. #Devoxx #ListJ9 @JosePaumard Some more bench • Results for Iterate HashSet SingletonSet TwoElementSet 1 7,3 ns 2,3 ns 2 9,5 ns 3,5 ns
  • 125. #Devoxx #ListJ9 @JosePaumard Conclusion • Many patterns from the GoF can be implemented with lambdas • We saw it for the template method • And used it for lists, sets and maps…  But should be avoided! • Avoiding pointer chasing = best performances!